Mercurial > hg > openttd
changeset 2244:eba7ec7edf28 draft
(svn r2764) -Feature: Clone vehicles
-This allows a player to clone an excisting vehicle of his own
-[fix]: this uncovered an excisting bug in CmdBuildRailVehicle() where depots could build trains of the wrong track type. This is fixed
-Thanks to Celestar for drawing the sprites and _luca_ for including them in openttd.grf
author | bjarni <bjarni@openttd.org> |
---|---|
date | Sun, 31 Jul 2005 13:08:08 +0000 |
parents | 1b3c000b1dfb |
children | 865d4c14214d |
files | aircraft_cmd.c aircraft_gui.c callback_table.c command.c command.h data/openttd.grf lang/english.txt roadveh_gui.c ship_gui.c spritecache.c table/sprites.h train_cmd.c train_gui.c vehicle.c |
diffstat | 14 files changed, 664 insertions(+), 116 deletions(-) [+] |
line wrap: on
line diff
--- a/aircraft_cmd.c +++ b/aircraft_cmd.c @@ -332,7 +332,7 @@ (_m[tile].m5 == 32 || _m[tile].m5 == 65 || _m[tile].m5 == 86); } -static bool CheckStoppedInHangar(Vehicle *v) +bool CheckStoppedInHangar(Vehicle *v) { if (!(v->vehstatus & VS_STOPPED) || !IsAircraftHangarTile(v->tile)) { _error_message = STR_A01B_AIRCRAFT_MUST_BE_STOPPED;
--- a/aircraft_gui.c +++ b/aircraft_gui.c @@ -89,6 +89,15 @@ } } +void CcCloneAircraft(bool success, uint tile, uint32 p1, uint32 p2) +{ + Vehicle *v; + + if (success) { + v = GetVehicle(_new_aircraft_id); + ShowAircraftViewWindow(v); + } +} static void NewAircraftWndProc(Window *w, WindowEvent *e) { @@ -496,11 +505,14 @@ { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 50, 67, 0x2B4, STR_A03B_REFIT_AIRCRAFT_TO_CARRY }, { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 68, 85, 0x2B2, STR_A028_SHOW_AIRCRAFT_S_ORDERS }, { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 86, 103, 0x2B3, STR_A02B_SHOW_AIRCRAFT_DETAILS }, +{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 32, 49, SPR_CLONE_AIRCRAFT, STR_CLONE_AIRCRAFT_INFO }, { WWT_PANEL, RESIZE_LRB, 14, 232, 249, 104, 103, 0x0, STR_NULL }, { WWT_RESIZEBOX, RESIZE_LRTB, 14, 238, 249, 104, 115, 0x0, STR_NULL }, { WIDGETS_END } }; +bool CheckStoppedInHangar(Vehicle *v); + static void AircraftViewWndProc(Window *w, WindowEvent *e) { switch(e->event) { @@ -587,6 +599,12 @@ case 10: /* show details */ ShowAircraftDetailsWindow(v); break; + case 11: { + /* clone vehicle */ + Vehicle *v; + v = GetVehicle(w->window_number); + DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneAircraft, CMD_CLONE_VEHICLE | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT)); + } break; } } break; @@ -602,6 +620,19 @@ DeleteWindowById(WC_VEHICLE_REFIT, w->window_number); DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number); break; + + case WE_MOUSELOOP: + { + Vehicle *v; + uint32 h; + v = GetVehicle(w->window_number); + h = CheckStoppedInHangar(v) ? (1<< 7) : (1 << 11); + if (h != w->hidden_state) { + w->hidden_state = h; + SetWindowDirty(w); + } + } break; + } } @@ -636,7 +667,7 @@ /* setup disabled buttons */ w->disabled_state = - IsTileOwner(tile, _local_player) ? 0 : ((1 << 4) | (1 << 7)); + IsTileOwner(tile, _local_player) ? 0 : ((1<<4) | (1<<7) | (1<<8)); /* determine amount of items for scroller */ num = 0; @@ -741,6 +772,42 @@ } } +/** + * Clones an aircraft + * @param *v is the original vehicle to clone + * @param *w is the window of the hangar where the clone is build + */ +static bool HandleCloneVehClick(Vehicle *v, Window *w) +{ + + if (!v){ + return false; + } + + if (v->type != VEH_Aircraft) { + // it's not an aircraft, do nothing + return false; + } + + + DoCommandP(w->window_number, v->index, _ctrl_pressed ? 1 : 0,CcCloneAircraft,CMD_CLONE_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE)); + + ResetObjectToPlace(); + + return true; +} + +static void ClonePlaceObj(uint tile, Window *w) +{ + Vehicle *v; + + + v = CheckMouseOverVehicle(); + if (v && HandleCloneVehClick(v, w)) + return; +} + + static void AircraftDepotWndProc(Window *w, WindowEvent *e) { switch(e->event) { @@ -754,14 +821,48 @@ AircraftDepotClickAircraft(w, e->click.pt.x, e->click.pt.y); break; case 7: /* show build aircraft window */ + ResetObjectToPlace(); ShowBuildAircraftWindow(w->window_number); break; - case 8: /* scroll to tile */ + + case 8: /* clone button */ + InvalidateWidget(w, 8); + TOGGLEBIT(w->click_state, 8); + + if (HASBIT(w->click_state, 8)) { + _place_clicked_vehicle = NULL; + SetObjectToPlaceWnd(SPR_CURSOR_CLONE, VHM_RECT, w); + } else { + ResetObjectToPlace(); + } + break; + case 9: /* scroll to tile */ + ResetObjectToPlace(); ScrollMainWindowToTile(w->window_number); break; } break; + +case WE_PLACE_OBJ: { + ClonePlaceObj(e->place.tile, w); + } break; + + case WE_ABORT_PLACE_OBJ: { + CLRBIT(w->click_state, 8); + InvalidateWidget(w, 8); + } break; + + // check if a vehicle in a depot was clicked.. + case WE_MOUSELOOP: { + Vehicle *v = _place_clicked_vehicle; + // since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button + if (v != NULL && HASBIT(w->click_state, 8)) { + _place_clicked_vehicle = NULL; + HandleCloneVehClick( v, w); + } + } break; + case WE_DESTROY: DeleteWindowById(WC_BUILD_VEHICLE, w->window_number); break; @@ -824,8 +925,9 @@ { WWT_MATRIX, RESIZE_RB, 14, 0, 295, 14, 61, 0x204, STR_A021_AIRCRAFT_CLICK_ON_AIRCRAFT}, { WWT_SCROLLBAR, RESIZE_LRB, 14, 319, 330, 14, 61, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, -{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 159, 62, 73, STR_A003_NEW_AIRCRAFT, STR_A022_BUILD_NEW_AIRCRAFT}, -{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 160, 318, 62, 73, STR_00E4_LOCATION, STR_A024_CENTER_MAIN_VIEW_ON_HANGAR}, +{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 105, 62, 73, STR_A003_NEW_AIRCRAFT, STR_A022_BUILD_NEW_AIRCRAFT}, +{WWT_NODISTXTBTN, RESIZE_TB, 14, 106, 212, 62, 73, STR_CLONE_AIRCRAFT, STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW}, +{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 213, 318, 62, 73, STR_00E4_LOCATION, STR_A024_CENTER_MAIN_VIEW_ON_HANGAR}, { WWT_PANEL, RESIZE_RTB, 14, 319, 318, 62, 73, 0x0, STR_NULL}, { WWT_RESIZEBOX, RESIZE_LRTB, 14, 319, 330, 62, 73, 0x0, STR_RESIZE_BUTTON}, { WIDGETS_END},
--- a/callback_table.c +++ b/callback_table.c @@ -10,6 +10,7 @@ /* aircraft_gui.c */ CommandCallback CcBuildAircraft; +CommandCallback CcCloneAircraft; /* airport_gui.c */ CommandCallback CcBuildAirport; @@ -41,13 +42,16 @@ /* roadveh_gui.c */ CommandCallback CcBuildRoadVeh; +CommandCallback CcCloneRoadVeh; /* ship_gui.c */ CommandCallback CcBuildShip; +CommandCallback CcCloneShip; /* train_gui.c */ CommandCallback CcBuildWagon; CommandCallback CcBuildLoco; +CommandCallback CcCloneTrain; CommandCallback *_callback_table[] = { /* 0x00 */ NULL, @@ -70,7 +74,11 @@ /* 0x11 */ CcPlaySound1D, /* 0x12 */ CcPlaySound1E, /* 0x13 */ CcStation, - /* 0x14 */ CcTerraform + /* 0x14 */ CcTerraform, + /* 0x15 */ CcCloneAircraft, + /* 0x16 */ CcCloneRoadVeh, + /* 0x17 */ CcCloneShip, + /* 0x18 */ CcCloneTrain, }; const int _callback_table_count = lengthof(_callback_table);
--- a/command.c +++ b/command.c @@ -159,6 +159,9 @@ DEF_COMMAND(CmdReplaceVehicle); +DEF_COMMAND(CmdCloneVehicle); + + /* The master command table */ static const Command _command_proc_table[] = { {CmdBuildRailroadTrack, 0}, /* 0 */ @@ -300,6 +303,7 @@ {CmdGiveMoney, 0}, /* 113 */ {CmdChangePatchSetting, CMD_SERVER}, /* 114 */ {CmdReplaceVehicle, 0}, /* 115 */ + {CmdCloneVehicle, 0}, /* 116 */ }; /* This function range-checks a cmd, and checks if the cmd is not NULL */
--- a/command.h +++ b/command.h @@ -136,6 +136,9 @@ CMD_CHANGE_PATCH_SETTING = 114, CMD_REPLACE_VEHICLE = 115, + + CMD_CLONE_VEHICLE = 116, + }; enum {
index d6166f23e22522fddf9bd000bcc0ff162e17ab79..5a784f20e5201f16a27c954d8f0172b990adb843 GIT binary patch literal 23690 zc%1FL4SW>Uxj%l+nc275*-f(9yb{7p5@5xs2m}I+5HN&*ioAN4m(qX~VMRsCtuJjY zc>&MNE)W96h)TmtZ3JsKh`1u+0+#G1p<NK2$(x-7v}Xe-qHAfdmEW075NPl3etLWR z|J?h(pWo)Qo0;7+XU_RP-{<>0&&=6Pgch3<0KkG_nII300wrJ}SPd}P0S<s>&;u?3 z02zZvQL1=F@oZ$=9x+Djgg3`Tk9#Adtk4_~t9EvUVgPCuYc?vXCa{XKE<w#lTR~*B zR=|1$4~`VmJ#{*nYS~<?xZMKw2xJbj0I~wQ$ahW4YbC3)+^t#Zp|suOj3Nr;E~sjQ z7}ev_+}aaH#qDu>V#ELyb(0YRw_<11UqBC8rM+fSDjka3$3_m)58p!@naC`1QvJY; z3~r^;rnq@%NziA>fDzermbZf<FddYGRbVZs0rl~jYT!%oHGsfXk?djsZ*^5Axvaba zh%UmTbqRzwx<nIjd(=eqtW8a1J#G^UI-oV=U^X&pXs{}p)Q!vuMRAjROuW_OR+JMY z5jI8c(&oV?k{G%tv;di5XaS>QYj7H!dE`+t0ZCTvesw+F(<<4P=5Uji$~J|YTeKZn z2zcBq+Z+xxv3ye~++68!dys(>D{Uf2%m!Db&BYxD7Hcw{ml52N3bMg1pb*>#mVhUK z54;5Sg4Y2u@=B#u;U$A0h`hp!g0O*cxvXxIFjx@WR+noF;8Rirw?}XZg3Bd%+(JqU zzXiCQygS7uh+3{T9Pv&v47$lg=u(G3k7i~?KG97kgr*V~bVlYe{3aBcMxmH*aCupm zi~Nh(8B2+|T+bTGeSDJJ$s<#eyOMJ!X~5#t?Et_~7Z?WesU?Pk5tMbK>Bz@XtIPt+ z!J}Xec$!*f8+a8QBWAc(V}oWj(Yh5hH@CE&Y;9?7CKlAvLKtE+Yz5(Pm@sT}bGTW{ zge~d-2Q<YhxEM59D>y4O*(x|Gae*?8W{+iW(%XuQUmwgML&qKh6I<E$Jtax6v? zX@7zs5GG;_@^o8Kl)mkKh{-FA4?HO$A;E5^-RRv}Ir@&?qMpa;WN6(ODB?mqrLK^* za~wxcWJIEXSK*)5Z-jP#p}tdy57rbyTf-RW#v1;t{u^iu79!q;$4Gh7$Uq?(D@~Wa zi&q62@K|Y!w2J{YzHtWRyF<usKlMIiwOad57)eJQujzdT#s<gqSV@UCxgjx<Mn*9% z-r80X8r#^46Y(JA5_*P2EBs?EF_#eYD1s|iKaHd?iYMkzA%&*`!LejCOWj%|<NV*z z3h0hVT|0O`J@Dvf(5;;%E7^x1Ux7p8LTe%`wb3kI@%Y0L3Azr|B0-FdHWaL&I0eTc zMQB(FG08wH3L@kDh1!@%JyKTq*VL@kW@~=vin7O7(=i9@18bl_a*zkttql784RrQo zCsdC*Lu;VgodfCHjK{5#U;8y=vuitHL2wPqSw#rrj)`PV_d<G_0`1og6vpmD_4Jsw zr;l#)uiTve{tR_Z^v~pLD27YI+n^_~^7L>o?zz1;tNUvx94!fc1>KRAxbXe-Ls>ne zA%3L<dbXD|UO6*-Z&uqv=zgmN;VHXH>I&s7v|>f?-d>)%`HF(=CEJHzsF$;PTeY7< zPj5La-BofvfAb6|)?)P&Sa3d@S*76G02KGCkSD8Td^(F&-9k(b)UQIk{p|i)3=7(` z=%Cl^4Qxpyg&h}a@%cY)FFAS)7j_P*UwNn`v_`rT(GHjI$M3CvKYvd-E^OU?44-)Q z?8!a*4j$?%+hE&}^{ZRyl)2vKi)Fe;;6(o*D89LbjA7hv_jM9p_)W_H@5zeC;!-?U zrQ{5ZWju-p|7iaVe^x&sBWFnfy6`yvXqGCpE7))x={$UlPG?-rXefp@_zNRr7>;wt z_uX%$A72f*a0sai9#=maDJm{x0N|T7mddqSvnH^TRjFFzRlQmZHlEP+H|&2cu*(qE z6&V-qPG@xiZXkX&uE&j6yffbZi$<WQds`jt3>QYoDSvmwui{nS^qqbwBH=y5H|zg{ zHHGp0D|_noeR=qSdWrsjJ+XH9E*z#??=RcC{Nn)h$XJSW<ahiW7oLB;7VnI-2h=>g z>g=a7-fM0S;D)yoYw@eEH3z(x8VY^wzUan75cIJE7q$ctCw@HT;<P@~Lg9k%-G7G` zSN|8#!jP;`0jnR%C`vM>^r#!l(zwMpj8jJ=UZ|O>^CPg=MB|v~7Wv?~$Y|=2$<X7k z>X)nFA(KmV32xC985bPQxJ0*_5vV#oE;5F!HM%$&w>@NyHjbs?+pUf!Ni^TFl7W#w z`d2|N8dC2kqp5HT+AZ2s$m-Ng+7w3cDB8HlV1I*&w{cESia`E_j3)aGoXbP;C&(I8 z?}nUqL>otAaEiy-pqXuUE=h3mDcVZX!?*-Y2(*$5s;ZTdFUT503hxw>>I;oFPEnFv zWL)&EsDxr7C7cjY)heo;l=(@DQd8Ldkv1;+E)rtVjmV7ys&+3FgQL}XFW{bZ<Z#g= zs6KZGRn;h3T`AZT8oe{vlCF+3TG#O@*iH6DTQmdYPHltM{m(RB=^WmJPx*U$kw;Wj z))lh~J0p12h2_oo)F*BJ-Xqb9qmk~J&4IdA`*EW``WaMvPZNLl`eT93crSj-e<}h6 zZOq<4?eIf5`sc8|pK|JoI-otUYx%{%`6u_{Za)-GbG=XO56Jahm)<XJrc!yj<WRty z7%DtBt{Fp5b5{E^Av$jF+V>L=uW83n(BJ8~OwzoUY6{Q2b_^fh)_Zx+E4nBiAil_j z$g97vEBw10;38y%QU9R>)TGyqr1T$!?+%Q*iT=y+6T$VA{-gArQFyO^6s7-2O8*G{ zeehFC|4};qM@or!RIorAEls9J6iBP33i2Z48w)A*8+7Ww&hR|ncPf_WW4xyK7bpmh z?EZsl@N*$28xtw-zaJ`Sd=)1)45FWQe-r&aF2IxUsK`hN=++PM@}n*E%scR_buS)k zrkuv7aksp!1Jd&+<K-<QA@@pyR3gpZ{|)5#CrVF9>-UX-wtZ#NtJ2%AFGKbO=|kyb z@AkL-Ogwk8hQoiISZPL6YisMtlP6p2mY@G|a1;&hG`%XM>DAcKNZ3*rIqQcpjXf+7 zyWi#?C>8elHMaGE-Xr?nD=W{fJ(u-*^@U+OD}n<lTJb+^Ig0UJ_jdg1;@plmK3LrK zP#|fS*(6eDbh%>W14Lgeemx1(5@9TwqYl_rbpBUo8_yrm!KzP(;yb$xJl~&?#jUI~ zjG|`8%kY}OG8j9;k&)L8UXxA=W&mh0$IWe`H4J?K&4durEX0HW(5#VkEgK>&IbziA z&_=3vY9q-wG6*5i3ZUH{Kd|p`dMII3tHy_%4Yo)^z(z*Y+kz7VQ|hwtuzD9BhL_-H zYPQ!O6aX}`@k1=v4ulaCJ+E0yT+YM%GH~f?*Hz|Qy75=9>MW#5soj26<!{tQ$l)@7 z87YM{T@6kN*|fP-7xO4-I2W!7{M=x-#o5^hg*uc9Bvx@5zSqEUj`dbtj>{w$0ybPj zc9^Z4dx6{e;1XiNuQF7Yq~-oH$YYfp=H?4a7K@@A3j+QUt2+-zi=Gz~){FB!!o2xn zEat)OZSB%sl7Pz^J<gN`LdyL4OQ@^~Zbw^tS6f$C%1#VLX*sU(pXNl5%abg)XoW;d z%xyg#o$Vc6PRTEOL+a5h-HVb6ADHKHQc-ktb#=CPb+mVBwPf2{tEDTFUp;LU=4U-H z*Arc6z@GND4($xz-qqRF-rm{O*4g$^=p(sUy3#&8Atuc7xKd&&?r87m=;|W(Y8$mp z#?JP(t`ujROA=~}j}13@+@g?F)zO`yokH#H(JZE;y_39XOj_bfp6BVECr7qpS_sYe zJh)hN#RLUMA0S~(Mx9++TXdzZy={JC`(lSj5R*mGo4y@03xx-JhqEFrc%$>+N702$ zTgUICU%>XZhY~uSN%PwlFLnzet(@jBkgj+ejGRYM1u^<SG`V*KYU_;VMqkxVn>{HH zCeHKFqP7&y^EP-dbzEXol=jYO4{VQKgl*B~Jw@6a+x)~NXOdfR(AsQ9%zMdq>b*j= z?xWt@&Rcq(ie89*Vd`9x6<oa7K~A&6yd|Qqa6{UKwb1_dCq(Y~ac?Ex-d5c<|ApY( z#Y;S{XgVzSrf*nyrZ8A`;djW{bE>!ZM}`z<`>e&i=H4ze&*ckk*zH^Uego|39m8}~ zB=!!6i=(})!-MCyrEf^waPfum-+T|Yk<)1Vyx!r+A=aPX;65_u0)qtixwRXLDcO>% z=d}-K1^0rb8xH#lKdEM{oS;pGwhhmI5bL=U&cnV9Bv1yeS}mS(@H@yoW8)NGsJ={h z+z&QZZrr>fv7zil66qly_fc7|Q#o-{-Olpfuh4b*)-OA3s(aaWDzNG5rlw6FzWXs! zlp_H=h3@_imqLY<HL1;IeIEu&f2rcBn~rXZ;L?5M(=O=Q^v$OCHoae8N?q^jKC)@Z zrsJDV*OihoOP~MI7|_#B+x$k_(@?6F)lY56h#$RCHsTEZNL(ug`})S6(kQysys2&T z5PX4dwQlNY{8}2(_ul@~(vx&6v`N{$L^{&Hb$Qceed}GN4#NKG*Py?&Y6i^`G#jl{ zctftbRIatT`DAOz#kX<|PL_(X3+J=oq|1i$sa}!MIA1G5A^Ik44K1m6qvn>-62IG! zAyP-J%Qq>-nWLLUR|DOeRG?&LHj&g|K5>|Hawp|At<A{|<=d1=^XBE`<|=vN%G_Kv zKS7z4o12r9u{=k~ZK=-5CHc0Ti6ZaH%gr5}vpfTk+aP_9%~7mwE!8-9aBfZkAgSh- z>fGE(xdp14%H-tbbkEW94a(r$JTa0VUc%($Dv?a2x}`Nt&W|(N)?c4<pX?!_DPoS; zHK)nb)D#Lei4AEcv8kyk92STX#{79qQ!Gq|8N;D)EX0QjwLGgU6b`$ZDM(=(S&W*R z)Vzcyj)tt}7QVTqIRUs^$RbDB)zlp3TexN#w^|Z#INU^>NwMbEW<G3hX=$+wZnvjN zAU`xTH^-V=XcyQuDXfY@b92}gZVp@3Jo7|FX;D=y5(g<tv%0ZsqEe8foXp8|tE%W~ ziDA)GOdQtS+=(seIXRh_3g~=8vBE2llN447XROpx9jY)%5d~4?m4|02ASZ8S4#_v< zD3sEXRLg1ra&mH4W~6IQqm>d`aFP6Iv6^ZqcBXj5P=4DSb53Ti;!bj=sQGU#f|=w_ zxPqkm9Y>#n?o+avg@SMcl)7gG(rq^;G9tcRyX&UJWqOUE{}a?7(}ZOZO&d1W3wo+D z2p1C(x6(i%2LA+ke-QFol(pLv60|S-lN9~HfEXOq?KIkKF%ekRwup%M)<)Y=M|3o4 z)5L!2VgZ846(XAY30zkaofS?)Zh?$Pl*A>CtBr!_(urL1N-YvOZ9d)DPY!E4=x3)H z-qsr0QI8uhvo<^B^bS9U8T%bZdqSMpB@89@{t?Cmdz{@Rtj_KRfwkKx!*hZqB%9S4 z-munSi?h7Me2wJ|f|0kynO<VOf$0sJ!5(LO34bHochaCwW>UhJ^btPC5GQ<nG0$;1 zx!-a=N9X*`;<GNTq@VRA&zHYn7U%sC%KNjk-d+v)y$!^Jew^|CYQI48d!Ox<X^z21 zSHHgBK!a_cszrG6z5km<6B2H;s46i3s6ojk@&!yFpTnE&iEOs015$g2L@MDzldCbQ zJ8sgDc+D+$j)+`Q#T#9-vEQaeaSxqjh<j+{&BoP?AbQjy?z)?H&ugq@MUHxE5r3nn zzOtX?c<Qa&6aLCu8&4akrKrma_M2U{@v^~|p!@BSe!neZb-&&3pcvigyhW_;ymbPj zyKgor=dQbNL$Td<vkPZ4)P)<0EjHUVH{RCo#v;ur*Rs5gx^j-~CRg6OpK>Yg&L#cs zoC8<a2_~-Jp@nM>T~a4NE|Syl(j{0RIi_nqU9x*bh#taaDjc_h<dE$1{bV`68oFC3 zSF|^Jv3_YsTmQCpGgB5Jn3)!53VZFMWQ5mAgHr?P__pAkxI~?ej!(q%Luv3hejKOO zZGsaUZYMlEt~d5CteFw`EqO?5(pvEELf!Q9bQ}s!!`pFMXeYis@Hv+8PHDaLtn_nf z2Yrpu=d;pZ+Q!I9{)?Nd{1@d(J(FHTmdy0{D8`NglfgXjD5wT6f&<_r_=IM=nQ#=G z4wu79_#!+APr>uhfCiyLG!v~r6=*Bk1p9|>P!zEi)Ff$6xCJ}4k!b!_d`n~k+=eIM zbi9x$RG!0+h1S<+7$zP+eq0RxoH;(AF0d0FKi+VdJzgkU>obwp78r^q&c~VlOsLQT zBNI=jugmG{a{OZOclDL@SjER5-2`LgCI9)IzhEXFFT|N|4Wxa|r&Zd0%yC7O9zObA zI8mw&Z>KOVlTL=x*@*+Tful9e1+)m+W0<Ijo0;g==xeG$<G8{BHH@gtr;q)M_aloq z5PW>~($xniQ7EPZH+Yc3@e~E57VHLZfF{rZdchUIK>?0~55OP5E$|I^27V50=oT~{ z%|gr2)5wRmqdll1%?X`6OmkLb+MqMGE;YqT-5)t)989xSX4rU=Vq#J`&Q_7BrJ9mq zTC6f7Ig)A<IIbeo3XLtu=@Qh81kTDDTEi`^(CK1QoiQ@k<T5bhTARaKE{sKTiNi3K z>UFc4M~k<+k&B^kgpn!SN~T&JFpaCsaKsQ(NOGY_mRYT?ip&^f3XzlUk%45Ikr_+V zHcl0c$y{<pCP#A%qgizEZWl*f(4|g>R+7pTaz>KMT4OE`$y8@BF3w7ZGYL$gmTq+E z4^hivkyA)ge`HLGB_lCc9l*q5oMyCmTzpJmQazj|8B>9Wi{+9mgG<!4&qxNcq9Ayp z8L*0MH{>M)>KZvv)ZBEagSBkN1D&MU>WDe2GGn=U4ydTP>W|eyNiEHiQxFSc1zap| z@C)!nlPZRa9D1>vlUpFhxZHxl+hHgiQU`?wB+_!XATOsNMit%xL%VmY*`dsYs_NGD z&fLdxb8>UGz}*um5JlQ3b8FSf>gv|{wIszjad%h<heNkB>#AFclMFM3u@G*pswP9U z#jsYJXAFfgrWlWb>&Oq7lPxtwLgBFLgzL1y?8#OiwStzX+F5J}2`X=Dtu_gv*48=5 zGBg*Qy?XZQ(&=C(W!Dn$2zVMi3+lkD;3)V25b$rn4s+mWSO(p28C(s20x{*-4)_W@ z0N;hp@B^q(7yJrBlz=i&9vY5{P${ZlQrAJ7EhT1!zzP{>r7>njkl0g<T%|c?Wtf;X z8Jf5%i!DakL~KSI<hV+n++koj*67l*Su0m%qfr;JF&7zzSc^KCW*n7?WLlCzj6pNU za;|V|GECsAlE@S*V-jO7qm}A^E17O{aFx!O)nXB;&bMgE2AIrMrI1HWoHg9s(%Kps z!lrVS>0}7BY00RiS=-8{aa9>)D>5XIAxtyJlB48>giNk7E0&6q!eQv-*i`N3Xx#wy zBg7<=e<cOTkfFV2bXEv9ltNy#rE||_#$r~d-Od}*$a6W=rv}<82T}LR5MxXh$J;6d z9%aUo;XuA}P%=-mu2fFoxeCFGGO1UkS~x4rbTL^@D|vu=UknbkRu1ALsT3$ak`Em; ze{*m!QzVnj)>wtWA$^nKDhH7tYN-r$l}IXej#Oxk<m=v`<|9h}{9#Ekm?<z>9?k`Y zSVc|&&J;Y9dahWWlqnQYCKtqV2g@0Gf=DbjE>@5$r&9{*oFyg(XXFvy7|YAes~$iM zaPV8mk~0uM@Y&T>C147e24;irg5}@`;F<WHz+cB1a}HdlBJF@KI04RwPr&EkTTp>t z!X$JXnvCY5N2o||K|9etRAES|FgPLNp}|>Uwi!??mf}pQF!Kme_zbp6lZ}Tc#?WwX zi|B%6;44jWLE<@RwpJvzAmkEAh67Q<Rwu+IiOLP@v^vQk<2qZPBvB|0R%GI@%aRT$ zxf{lHsWM5|B?|8l3U8(DTUF8-R$(hdi0-i*GR24;j#aaCph=bq+QwEUi5w9q<O0<r zhox|RLZ3#dC2=t-vB<VU7jJb@fl6bMZjAd(NwJMq(UnVB=%RVnfHa5%hNY(2VvbQA zvgYb{3aLm%3hfNc6Fkrm+h%gbs0ImIp`M&+d1hU`7?77sCRnKPpgFdMQ`9`NfQpoX z2#hG0$t12%iE6nMO+gX4T<X9C&kL~6ss#nPREHvikV{ktB(^la01NVRb7BQKgY#%& z6&gg}q^f0Pavsag8=PCqg(}yEveiuEo;|I|kf)}z72(Qet&j{ioZNHwo;@U=si<sL z?_k5NCk5h!cWX|vkiHcrrA(`U$pp=bn!;o(xz$t=ZpHXyE1838c&%EyMROSSD}O$_ zwhcB%5}8(<sO>SeVxhI#5hBy>r^=KA{&Mx))u;ND>3hHfo}h8>XW$iZ1e^vR)2L^K zgWyOw8P0_d!pGp#a2>3HFTj^!BRmY7;Az+e3H$<n19_B+M3hgHgh{AkQ0lsYab-dS zY}SfFPLyG@!7Q#)u-ln5o6QOba8(17?RM(d>4tQ!I@3yQ)akWMDiUl4$uwFkvU!w5 zMze8M$hN=%eC0r^jY-fZBqeifN^;9d>dSm(md%E2<a>#UoY7%TZfR+4smie0Yz$$I zR;pVPO-z`Rtu16Iw2<{Co|Em?<YtmgoJ=!g(l$~Blx$>ULd!{-y|y4jsx7X1+E!*= z0#9Z#Ee1yYEfq#>dn&Z^m5JdNh^z*K)0u3uLn}|!^9Obl>K7%*@l;)(<N7>n9rY|? zw_bCuN;9uzn*05WSJUFcWVY(wrP6%Bdd;gMsc~njH2sY(p?+O5bGpaqx@00x{Rg@< ziRuz4xW@kqa}4W*r#y7UB+Bl7Ws+cyAm+xSstj`ra&-RY<POG&DpHJa#=I&+Uhd$f zz+y4Q(?yp9q=9TO1l$1%!Nj;eRUw)Tu7irp=~56>oRzFoc^1$Bnx<I{Bj3Gy#5<~m z8F}|4)xsVb@y<J{1C5vzvP5pL0TzyncY3Q63<ATzXfTPUU-Q8-u$s!91Vj&g(A3!@ z0nf>}g<9M)v8o)?j6H;pSVO#ORnwt6Vuj%luf_LaNG)P8#)L6oj|U@dh4u&suPs)X zqAyk$PKQ1T%%SIb3dmqP_$7Fq(me!Dfp*YCQ@zXJ&tNU6w(Z)r>%e+`*B<&ffUUds z{4ycomwOHvnRxE2IapfVC8!S8?Ga+c0T1{c7J<UANZhUip)qh%D47(%1L`ceF_NcF zHXNW2uR2Pd!|d55YZF5}l*oOdG=v$gSQF8+Owa;RXe3-ud)~84S+C`xT`|p!+`Gs& zl1N^HoR+R`{p+hRdZ9_unWCa1!qg-iCr+Y|iS;SwqVac4yqi86Qb;noOV^0Iivtsk zMH9x4FPfy?0w)D$lVo<ngu9B>TLMm|ctSBrtGf#p(O^BkNSztH3l$ZUp-j=_lF%~s zW#aUwg!X98;IQDE5fv2yG9lE=QXG_!85K<?mr0^Ira#1(sG4DsYPZBZZj9a3fV2oo ztS{0^w0qQXk%^>OyBmtQ2p2W1y<Rl``*(37eBB`0R?vi-E`$`5`=Q<6Upou^wewoC z3EG1F^|L_h=Ob94^>cY&{oHNV@7W~xT@FDpUi-F!9vQzP!pAG<M*gUyo7T>Lu@6tb z5V;Z%O+|g6hD7pIIE|96>RWK>A*+!fh6d>f3lw4X!Nyv3kcsPuc_N&IX%X3NCWHE* zo`{R}8%S)Cj(4tqapPrZ>!EmQgLKp@)W!Q9$ey4UlL>L;cfq2)BihS|;1|2uhT_Ot zzu1=BuvV=Pf0sOXYEoS=Zi1d)5#0#UN|M;1S?o940mkYD^G&8Gt}oY?Yme<LRu@IS zPnK#Akw;!B$K{dow^#RKT&@Nww4B(}f2o5ke|tX}#9S|6rT;Muj5O1L9U~0nR1<Ah zM5vr_E?QjZH=^{}N6ZEfowl2>bmUaO`ql%SniAmSs{oG95AaCj8XpPr(AD5n`Txhq z{~8}_g0w<sdS4?ZN=K=f1-#wWThCrIN66eD+-Q*cViVVAlJ^rr{O01gQI6jp;id9Z zzi7FyW7gZN+c9+QU8eF4H(Y#UL@`D=dCv`;6#u(98G6&=vGG=&FCH=hO)MhjC}YE- zDCmD!(AjB)SaYflqu{|Fp-8i6PR<jf1dh2l52son7b&7SYch(7#H?CWS8yo}T`Sch zvl#biPb^~5p46AeIQ5r-NC5wjum2cdd&^keT0PCsLmrG93kUz!SoK<O2x2w+TZ3W2 zdXvTIVZ}&vkwN_?t1GXsKl_;0AeGZ**NsMkZ?Epby3GXr<(A%oH(p96cl;HXXPiLL zF%<mq>L0(oy=(+nUofk�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
--- a/lang/english.txt +++ b/lang/english.txt @@ -2404,6 +2404,12 @@ STR_881D_NEW_MONORAIL_VEHICLES :{WHITE}New Monorail Vehicles STR_881E_NEW_MAGLEV_VEHICLES :{WHITE}New Maglev Vehicles STR_881F_BUILD_VEHICLE :{BLACK}Build Vehicle +STR_CLONE_ROAD_VEHICLE :{BLACK}Clone Vehicle +STR_CLONE_ROAD_VEHICLE_INFO :{BLACK}This will build a copy of the road vehicle. Control-click will share the orders +STR_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}This will build a copy of a road vehicle. Click this button and then on a road vehicle inside or outside the depot. Control-click will share the orders +STR_CLONE_TRAIN :{BLACK}Clone Train +STR_CLONE_TRAIN_INFO :{BLACK}This will build a copy of the train including all cars. Control-click will share the orders +STR_CLONE_TRAIN_DEPOT_INFO :{BLACK}This will build a copy of a train including all cars. Click this button and then on a train inside or outside the depot. Control-click will share the orders STR_8820_RENAME :{BLACK}Rename STR_8823_SKIP :{BLACK}Skip STR_8824_DELETE :{BLACK}Delete @@ -2560,6 +2566,9 @@ STR_9807_MUST_BUILD_SHIP_DEPOT_FIRST :{WHITE}Must build ship depot first STR_9808_NEW_SHIPS :{WHITE}New Ships STR_9809_BUILD_SHIP :{BLACK}Build Ship +STR_CLONE_SHIP :{BLACK}Clone Ship +STR_CLONE_SHIP_INFO :{BLACK}This will build a copy of the ship. Control-click will share the orders +STR_CLONE_SHIP_DEPOT_INFO :{BLACK}This will build a copy of a ship. Click this button and then on a ship inside or outside the depot. Control-click will share the orders STR_980B_SHIP_MUST_BE_STOPPED_IN :{WHITE}Ship must be stopped in depot STR_980C_CAN_T_SELL_SHIP :{WHITE}Can't sell ship... STR_980D_CAN_T_BUILD_SHIP :{WHITE}Can't build ship... @@ -2624,6 +2633,9 @@ STR_A001_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Can't build airport here... STR_A002_AIRCRAFT_HANGAR :{WHITE}{STATION} Aircraft Hangar STR_A003_NEW_AIRCRAFT :{BLACK}New Aircraft +STR_CLONE_AIRCRAFT :{BLACK}Clone Aircraft +STR_CLONE_AIRCRAFT_INFO :{BLACK}This will build a copy of the aircraft. Control-click will share the orders +STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}This will build a copy of an aircraft. Click this button and then on an aircraft inside or outside the hangar. Control-click will share the orders STR_A004_INFORMATION :{BLACK}Information STR_A005_NEW_AIRCRAFT :{WHITE}New Aircraft STR_A006_BUILD_AIRCRAFT :{BLACK}Build Aircraft
--- a/roadveh_gui.c +++ b/roadveh_gui.c @@ -230,6 +230,16 @@ w->caption_color = v->owner; } +void CcCloneRoadVeh(bool success, uint tile, uint32 p1, uint32 p2) +{ + Vehicle *v; + + if (!success) return; + + v = GetVehicle(_new_roadveh_id); + ShowRoadVehViewWindow(v); +} + static void RoadVehViewWndProc(Window *w, WindowEvent *e) { switch(e->event) { @@ -308,6 +318,12 @@ case 10: /* show details */ ShowRoadVehDetailsWindow(v); break; + case 11: { + /* clone vehicle */ + Vehicle *v; + v = GetVehicle(w->window_number); + DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneRoadVeh, CMD_CLONE_VEHICLE | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE)); + } break; } } break; @@ -322,6 +338,18 @@ DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number); DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number); break; + + case WE_MOUSELOOP: + { + Vehicle *v; + uint32 h; + v = GetVehicle(w->window_number); + h = IsTileDepotType(v->tile, TRANSPORT_ROAD) && (v->vehstatus&VS_STOPPED) ? (1<< 7) : (1 << 11); + if (h != w->hidden_state) { + w->hidden_state = h; + SetWindowDirty(w); + } + } } } @@ -337,6 +365,7 @@ { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 50, 67, 0x2CB, STR_9020_FORCE_VEHICLE_TO_TURN_AROUND }, { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 68, 85, 0x2B2, STR_901D_SHOW_VEHICLE_S_ORDERS }, { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 86, 103, 0x2B3, STR_9021_SHOW_ROAD_VEHICLE_DETAILS }, +{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 32, 49, SPR_CLONE_ROADVEH, STR_CLONE_ROAD_VEHICLE_INFO }, { WWT_PANEL, RESIZE_LRB, 14, 232, 249, 104, 103, 0x0, STR_NULL }, { WWT_RESIZEBOX, RESIZE_LRTB, 14, 238, 249, 104, 115, 0x0, STR_NULL }, { WIDGETS_END } @@ -536,7 +565,7 @@ /* setup disabled buttons */ w->disabled_state = - IsTileOwner(tile, _local_player) ? 0 : ((1 << 4) | (1 << 7)); + IsTileOwner(tile, _local_player) ? 0 : ((1<<4) | (1<<7) | (1<<8)); /* determine amount of items for scroller */ num = 0; @@ -640,6 +669,41 @@ } } +/** + * Clones a road vehicle + * @param *v is the original vehicle to clone + * @param *w is the window of the depot where the clone is build + */ +static bool HandleCloneVehClick(Vehicle *v, Window *w) +{ + + if (!v){ + return false; + } + + if (v->type != VEH_Road) { + // it's not a road vehicle, do nothing + return false; + } + + + DoCommandP(w->window_number, v->index, _ctrl_pressed ? 1 : 0,CcCloneRoadVeh,CMD_CLONE_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE)); + + ResetObjectToPlace(); + + return true; +} + +static void ClonePlaceObj(uint tile, Window *w) +{ + Vehicle *v; + + + v = CheckMouseOverVehicle(); + if (v && HandleCloneVehClick(v, w)) + return; +} + static void RoadDepotWndProc(Window *w, WindowEvent *e) { switch(e->event) { @@ -654,12 +718,45 @@ break; case 7: + ResetObjectToPlace(); ShowBuildRoadVehWindow(w->window_number); break; + + case 8: /* clone button */ + InvalidateWidget(w, 8); + TOGGLEBIT(w->click_state, 8); + + if (HASBIT(w->click_state, 8)) { + _place_clicked_vehicle = NULL; + SetObjectToPlaceWnd(SPR_CURSOR_CLONE, VHM_RECT, w); + } else { + ResetObjectToPlace(); + } + break; + + case 9: /* scroll to tile */ + ResetObjectToPlace(); + ScrollMainWindowToTile(w->window_number); + break; + } + } break; + + case WE_PLACE_OBJ: { + ClonePlaceObj(e->place.tile, w); + } break; - case 8: /* scroll to tile */ - ScrollMainWindowToTile(w->window_number); - break; + case WE_ABORT_PLACE_OBJ: { + CLRBIT(w->click_state, 8); + InvalidateWidget(w, 8); + } break; + + // check if a vehicle in a depot was clicked.. + case WE_MOUSELOOP: { + Vehicle *v = _place_clicked_vehicle; + // since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button + if (v != NULL && HASBIT(w->click_state, 8)) { + _place_clicked_vehicle = NULL; + HandleCloneVehClick( v, w); } } break; @@ -729,8 +826,9 @@ { WWT_MATRIX, RESIZE_RB, 14, 0, 279, 14, 55, 0x305, STR_9022_VEHICLES_CLICK_ON_VEHICLE}, { WWT_SCROLLBAR, RESIZE_LRB, 14, 303, 314, 14, 55, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, -{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 150, 56, 67, STR_9004_NEW_VEHICLES, STR_9023_BUILD_NEW_ROAD_VEHICLE}, -{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 151, 302, 56, 67, STR_00E4_LOCATION, STR_9025_CENTER_MAIN_VIEW_ON_ROAD}, +{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 100, 56, 67, STR_9004_NEW_VEHICLES, STR_9023_BUILD_NEW_ROAD_VEHICLE}, +{WWT_NODISTXTBTN, RESIZE_TB, 14, 101, 200, 56, 67, STR_CLONE_ROAD_VEHICLE, STR_CLONE_ROAD_VEHICLE_DEPOT_INFO}, +{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 201, 302, 56, 67, STR_00E4_LOCATION, STR_9025_CENTER_MAIN_VIEW_ON_ROAD}, { WWT_PANEL, RESIZE_RTB, 14, 303, 302, 56, 67, 0x0, STR_NULL}, { WWT_RESIZEBOX, RESIZE_LRTB, 14, 303, 314, 56, 67, 0x0, STR_RESIZE_BUTTON}, { WIDGETS_END},
--- a/ship_gui.c +++ b/ship_gui.c @@ -320,6 +320,15 @@ ShowShipViewWindow(v); } +void CcCloneShip(bool success, uint tile, uint32 p1, uint32 p2) +{ + Vehicle *v; + if (!success) return; + + v = GetVehicle(_new_ship_id); + ShowShipViewWindow(v); +} + static void NewShipWndProc(Window *w, WindowEvent *e) { switch(e->event) { @@ -465,60 +474,60 @@ static void ShipViewWndProc(Window *w, WindowEvent *e) { switch(e->event) { - case WE_PAINT: { - Vehicle *v = GetVehicle(w->window_number); - uint32 disabled = 1<<8; - StringID str; + case WE_PAINT: { + Vehicle *v = GetVehicle(w->window_number); + uint32 disabled = 1<<8; + StringID str; - // Possible to refit? - if (ShipVehInfo(v->engine_type)->refittable && + // Possible to refit? + if (ShipVehInfo(v->engine_type)->refittable && v->vehstatus&VS_STOPPED && v->u.ship.state == 0x80 && IsTileDepotType(v->tile, TRANSPORT_WATER)) - disabled = 0; + disabled = 0; - if (v->owner != _local_player) - disabled |= 1<<8 | 1<<7; - w->disabled_state = disabled; + if (v->owner != _local_player) + disabled |= 1<<8 | 1<<7; + w->disabled_state = disabled; - /* draw widgets & caption */ - SetDParam(0, v->string_id); - SetDParam(1, v->unitnumber); - DrawWindowWidgets(w); + /* draw widgets & caption */ + SetDParam(0, v->string_id); + SetDParam(1, v->unitnumber); + DrawWindowWidgets(w); - if (v->breakdown_ctr == 1) { - str = STR_885C_BROKEN_DOWN; - } else if (v->vehstatus & VS_STOPPED) { - str = STR_8861_STOPPED; - } else { - switch (v->current_order.type) { - case OT_GOTO_STATION: { - SetDParam(0, v->current_order.station); - SetDParam(1, v->cur_speed * 10 >> 5); - str = STR_HEADING_FOR_STATION + _patches.vehicle_speed; - } break; + if (v->breakdown_ctr == 1) { + str = STR_885C_BROKEN_DOWN; + } else if (v->vehstatus & VS_STOPPED) { + str = STR_8861_STOPPED; + } else { + switch (v->current_order.type) { + case OT_GOTO_STATION: { + SetDParam(0, v->current_order.station); + SetDParam(1, v->cur_speed * 10 >> 5); + str = STR_HEADING_FOR_STATION + _patches.vehicle_speed; + } break; - case OT_GOTO_DEPOT: { - Depot *depot = GetDepot(v->current_order.station); - SetDParam(0, depot->town_index); - SetDParam(1, v->cur_speed * 10 >> 5); - str = STR_HEADING_FOR_SHIP_DEPOT + _patches.vehicle_speed; - } break; + case OT_GOTO_DEPOT: { + Depot *depot = GetDepot(v->current_order.station); + SetDParam(0, depot->town_index); + SetDParam(1, v->cur_speed * 10 >> 5); + str = STR_HEADING_FOR_SHIP_DEPOT + _patches.vehicle_speed; + } break; - case OT_LOADING: - case OT_LEAVESTATION: - str = STR_882F_LOADING_UNLOADING; - break; - - default: - if (v->num_orders == 0) { - str = STR_NO_ORDERS + _patches.vehicle_speed; - SetDParam(0, v->cur_speed * 10 >> 5); - } else - str = STR_EMPTY; - break; + case OT_LOADING: + case OT_LEAVESTATION: + str = STR_882F_LOADING_UNLOADING; + break; + + default: + if (v->num_orders == 0) { + str = STR_NO_ORDERS + _patches.vehicle_speed; + SetDParam(0, v->cur_speed * 10 >> 5); + } else + str = STR_EMPTY; + break; + } } - } /* draw the flag plus orders */ DrawSprite(v->vehstatus & VS_STOPPED ? 0xC12 : 0xC13, 2, w->widget[5].top + 1); @@ -526,43 +535,61 @@ DrawWindowViewport(w); } break; - case WE_CLICK: { - Vehicle *v = GetVehicle(w->window_number); + case WE_CLICK: { + Vehicle *v = GetVehicle(w->window_number); - switch(e->click.widget) { - case 5: /* start stop */ - DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_SHIP | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP)); - break; - case 6: /* center main view */ - ScrollMainWindowTo(v->x_pos, v->y_pos); - break; - case 7: /* goto hangar */ - DoCommandP(v->tile, v->index, 0, NULL, CMD_SEND_SHIP_TO_DEPOT | CMD_MSG(STR_9819_CAN_T_SEND_SHIP_TO_DEPOT)); - break; - case 8: /* refit */ - ShowShipRefitWindow(v); - break; - case 9: /* show orders */ - ShowOrdersWindow(v); + switch(e->click.widget) { + case 5: /* start stop */ + DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_SHIP | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP)); + break; + case 6: /* center main view */ + ScrollMainWindowTo(v->x_pos, v->y_pos); + break; + case 7: /* goto hangar */ + DoCommandP(v->tile, v->index, 0, NULL, CMD_SEND_SHIP_TO_DEPOT | CMD_MSG(STR_9819_CAN_T_SEND_SHIP_TO_DEPOT)); + break; + case 8: /* refit */ + ShowShipRefitWindow(v); + break; + case 9: /* show orders */ + ShowOrdersWindow(v); + break; + case 10: /* show details */ + ShowShipDetailsWindow(v); + break; + case 11: { + /* clone vehicle */ + Vehicle *v; + v = GetVehicle(w->window_number); + DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneShip, CMD_CLONE_VEHICLE | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP)); + } break; + } + } break; + + case WE_RESIZE: + w->viewport->width += e->sizing.diff.x; + w->viewport->height += e->sizing.diff.y; + w->viewport->virtual_width += e->sizing.diff.x; + w->viewport->virtual_height += e->sizing.diff.y; break; - case 10: /* show details */ - ShowShipDetailsWindow(v); + + case WE_DESTROY: + DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number); + DeleteWindowById(WC_VEHICLE_REFIT, w->window_number); + DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number); break; - } - } break; - case WE_RESIZE: - w->viewport->width += e->sizing.diff.x; - w->viewport->height += e->sizing.diff.y; - w->viewport->virtual_width += e->sizing.diff.x; - w->viewport->virtual_height += e->sizing.diff.y; - break; - - case WE_DESTROY: - DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number); - DeleteWindowById(WC_VEHICLE_REFIT, w->window_number); - DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number); - break; + case WE_MOUSELOOP: + { + Vehicle *v; + uint32 h; + v = GetVehicle(w->window_number); + h = IsTileDepotType(v->tile, TRANSPORT_WATER) && v->vehstatus & VS_HIDDEN ? (1<< 7) : (1 << 11); + if (h != w->hidden_state) { + w->hidden_state = h; + SetWindowDirty(w); + } + } } } @@ -578,6 +605,7 @@ { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 50, 67, 0x2B4, STR_983A_REFIT_CARGO_SHIP_TO_CARRY}, { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 68, 85, 0x2B2, STR_9828_SHOW_SHIP_S_ORDERS}, { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 86, 103, 0x2B3, STR_982B_SHOW_SHIP_DETAILS}, +{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 32, 49, SPR_CLONE_SHIP, STR_CLONE_SHIP_INFO}, { WWT_PANEL, RESIZE_LRB, 14, 232, 249, 104, 103, 0x0, STR_NULL }, { WWT_RESIZEBOX, RESIZE_LRTB, 14, 238, 249, 104, 115, 0x0, STR_NULL }, { WIDGETS_END } @@ -720,6 +748,41 @@ } } +/** + * Clones a ship + * @param *v is the original vehicle to clone + * @param *w is the window of the depot where the clone is build + */ +static bool HandleCloneVehClick(Vehicle *v, Window *w) +{ + + if (!v){ + return false; + } + + if (v->type != VEH_Ship) { + // it's not a ship, do nothing + return false; + } + + + DoCommandP(w->window_number, v->index, _ctrl_pressed ? 1 : 0,CcCloneShip,CMD_CLONE_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE)); + + ResetObjectToPlace(); + + return true; +} + +static void ClonePlaceObj(uint tile, Window *w) +{ + Vehicle *v; + + + v = CheckMouseOverVehicle(); + if (v && HandleCloneVehClick(v, w)) + return; +} + static void ShipDepotWndProc(Window *w, WindowEvent *e) { switch(e->event) { case WE_PAINT: @@ -733,14 +796,49 @@ break; case 7: + ResetObjectToPlace(); ShowBuildShipWindow(w->window_number); break; + + case 8: /* clone button */ + InvalidateWidget(w, 8); + TOGGLEBIT(w->click_state, 8); + + if (HASBIT(w->click_state, 8)) { + _place_clicked_vehicle = NULL; + SetObjectToPlaceWnd(SPR_CURSOR_CLONE, VHM_RECT, w); + } else { + ResetObjectToPlace(); + } + break; - case 8: /* scroll to tile */ + case 9: /* scroll to tile */ + ResetObjectToPlace(); ScrollMainWindowToTile(w->window_number); break; } break; + + case WE_PLACE_OBJ: { + //ClonePlaceObj(e->place.tile, w); + ClonePlaceObj(w->window_number, w); + } break; + + case WE_ABORT_PLACE_OBJ: { + CLRBIT(w->click_state, 8); + InvalidateWidget(w, 8); + } break; + + // check if a vehicle in a depot was clicked.. + case WE_MOUSELOOP: { + Vehicle *v = _place_clicked_vehicle; + + // since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button + if (v != NULL && HASBIT(w->click_state, 8)) { + _place_clicked_vehicle = NULL; + HandleCloneVehClick(v, w); + } + } break; case WE_DESTROY: DeleteWindowById(WC_BUILD_VEHICLE, w->window_number); @@ -804,8 +902,9 @@ { WWT_MATRIX, RESIZE_RB, 14, 0, 269, 14, 61, 0x203, STR_981F_SHIPS_CLICK_ON_SHIP_FOR}, { WWT_SCROLLBAR, RESIZE_LRB, 14, 293, 304, 14, 61, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, -{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 146, 62, 73, STR_9804_NEW_SHIPS, STR_9820_BUILD_NEW_SHIP}, -{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 147, 292, 62, 73, STR_00E4_LOCATION, STR_9822_CENTER_MAIN_VIEW_ON_SHIP}, +{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 96, 62, 73, STR_9804_NEW_SHIPS, STR_9820_BUILD_NEW_SHIP}, +{WWT_NODISTXTBTN, RESIZE_TB, 14, 97, 194, 62, 73, STR_CLONE_SHIP, STR_CLONE_SHIP_DEPOT_INFO}, +{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 195, 292, 62, 73, STR_00E4_LOCATION, STR_9822_CENTER_MAIN_VIEW_ON_SHIP}, { WWT_PANEL, RESIZE_RTB, 14, 293, 292, 62, 73, 0x0, STR_NULL}, { WWT_RESIZEBOX, RESIZE_LRTB, 14, 293, 304, 62, 73, 0x0, STR_RESIZE_BUTTON}, { WIDGETS_END},
--- a/spritecache.c +++ b/spritecache.c @@ -732,7 +732,7 @@ "cached_sprites.xx3", }; -#define OPENTTD_SPRITES_COUNT 98 +#define OPENTTD_SPRITES_COUNT 100 static const SpriteID _openttd_grf_indexes[] = { SPR_OPENTTD_BASE + 0, SPR_OPENTTD_BASE + 7, // icons etc 134, 134, // euro symbol medium size
--- a/table/sprites.h +++ b/table/sprites.h @@ -64,6 +64,11 @@ SPR_ARROW_LEFT = SPR_OPENTTD_BASE + 97, SPR_ARROW_RIGHT = SPR_OPENTTD_BASE + 98, + /* Clone vehicles stuff */ + SPR_CLONE_AIRCRAFT = SPR_OPENTTD_BASE + 99, + SPR_CLONE_ROADVEH = SPR_OPENTTD_BASE + 99, + SPR_CLONE_TRAIN = SPR_OPENTTD_BASE + 99, + SPR_CLONE_SHIP = SPR_OPENTTD_BASE + 99, /* Network GUI sprites */ SPR_SQUARE = SPR_OPENTTD_BASE + 23, // colored square (used for newgrf compatibility) @@ -942,6 +947,8 @@ SPR_CURSOR_BUS_STATION = 2725, SPR_CURSOR_TRUCK_STATION = 2726, SPR_CURSOR_ROAD_TUNNEL = 2433, + + SPR_CURSOR_CLONE = SPR_OPENTTD_BASE + 100, } CursorSprite; /// Animation macro in table/animcursors.h (_animcursors[])
--- a/train_cmd.c +++ b/train_cmd.c @@ -568,7 +568,7 @@ /** Build a railroad vehicle. * @param x,y tile coordinates (depot) where rail-vehicle is built * @param p1 engine type id - * @param p2 unused + * @param p2 build only one engine, even if it is a dualheaded engine. It also prevents any free cars from being added to the train */ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) { @@ -594,10 +594,19 @@ SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); rvi = RailVehInfo(p1); + e = GetEngine(p1); + + /* Check if depot and new engine uses the same kind of tracks */ + if (!IsCompatibleRail(e->railtype, GetRailType(tile))) return CMD_ERROR; if (rvi->flags & RVI_WAGON) return CmdBuildRailWagon(p1, tile, flags); value = EstimateTrainCost(rvi); + + //make sure we only pay for half a dualheaded engine if we only requested half of it + if (rvi->flags&RVI_MULTIHEAD && HASBIT(p2,0)) + value /= 2; + if (!(flags & DC_QUERY_COST)) { v = AllocateVehicle(); @@ -633,7 +642,6 @@ v->dest_tile = 0; v->engine_type = (byte)p1; - e = GetEngine(p1); v->reliability = e->reliability; v->reliability_spd_dec = e->reliability_spd_dec; @@ -651,12 +659,16 @@ VehiclePositionChanged(v); - if (rvi->flags&RVI_MULTIHEAD && (u = AllocateVehicle()) != NULL) - AddRearEngineToMultiheadedTrain(v, u, true); + if (rvi->flags&RVI_MULTIHEAD && (u = AllocateVehicle()) != NULL && !HASBIT(p2,0)) { + AddRearEngineToMultiheadedTrain(v, u, true); + } TrainConsistChanged(v); UpdateTrainAcceleration(v); - NormalizeTrainVehInDepot(v); + + if (!HASBIT(p2,0)) { // do not move the cars if HASBIT(p2,0) is set + NormalizeTrainVehInDepot(v); + } InvalidateWindow(WC_VEHICLE_DEPOT, tile); RebuildVehicleLists(); @@ -1472,10 +1484,7 @@ /** Refits a train to the specified cargo type. * @param x,y unused * @param p1 vehicle ID of the train to refit - * @param p2 various bitstuffed elements - * - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF) - * - p2 = (bit 8) - skip check for stopped in depot, used by autoreplace (p2 & 0x100) - * @todo p2 bit8 check <b>NEEDS TO GO</b> + * @param p2 the new cargo type to refit to (p2 & 0xFF) */ int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) { @@ -1483,14 +1492,13 @@ int32 cost; uint num; CargoID new_cid = p2 & 0xFF; //gets the cargo number - bool SkipStoppedInDepotCheck = !!HASBIT(p2, 8); // XXX - needs to go, yes? if (!IsVehicleIndex(p1)) return CMD_ERROR; v = GetVehicle(p1); if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; - if (!SkipStoppedInDepotCheck && CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED); + if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED); /* Check cargo */ if (new_cid > NUM_CARGO) return CMD_ERROR; @@ -1537,10 +1545,7 @@ cost += (_price.build_railvehicle >> 8); num += amount; if (flags & DC_EXEC) { - //autorefitted train cars wants to keep the cargo - //it will be checked if the cargo is valid in CmdReplaceVehicle - if (!(SkipStoppedInDepotCheck)) - v->cargo_count = 0; + v->cargo_count = 0; v->cargo_type = new_cid; v->cargo_cap = amount; InvalidateWindow(WC_VEHICLE_DETAILS, v->index); @@ -1548,8 +1553,7 @@ } } } - // SkipStoppedInDepotCheck is called by CmdReplace and it should only apply to the single car it is called for - } while ( (v=v->next) != NULL || SkipStoppedInDepotCheck ); + } while ( (v=v->next) != NULL ); _returned_refit_amount = num;
--- a/train_gui.c +++ b/train_gui.c @@ -154,6 +154,17 @@ ShowTrainViewWindow(v); } +void CcCloneTrain(bool success, uint tile, uint32 p1, uint32 p2) +{ + Vehicle *v; + + if (!success) + return; + + v = GetVehicle(_new_train_id); + ShowTrainViewWindow(v); +} + static void engine_drawing_loop(int *x, int *y, int *pos, int *sel, int *selected_id, byte railtype, byte show_max, bool is_engine) { @@ -366,7 +377,7 @@ /* setup disabled buttons */ w->disabled_state = - IsTileOwner(tile, _local_player) ? 0 : ((1 << 4) | (1 << 5) | (1 << 8)); + IsTileOwner(tile, _local_player) ? 0 : ((1 << 4) | (1 << 5) | (1 << 8) | (1<<9)); /* determine amount of items for scroller */ num = 0; @@ -580,6 +591,47 @@ } } +/** + * Clones a train + * @param *v is the original vehicle to clone + * @param *w is the window of the depot where the clone is build + */ +static bool HandleCloneVehClick(Vehicle *v, Window *w) +{ + + if (!v){ + return false; + } + + // for train vehicles: subtype 0 for locs and not zero for others + if (v->type == VEH_Train && v->subtype != 0) { + v = GetFirstVehicleInChain(v); + if (v->subtype != 0) // This happens when clicking on a train in depot with no loc attached + return false; + }else{ + if (v->type != VEH_Train) { + // it's not a train, Do Nothing + return false; + } + } + + DoCommandP(w->window_number, v->index, _ctrl_pressed ? 1 : 0, CcCloneTrain, CMD_CLONE_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE)); + + ResetObjectToPlace(); + + return true; +} + +static void ClonePlaceObj(uint tile, Window *w) +{ + Vehicle *v; + + + v = CheckMouseOverVehicle(); + if (v && HandleCloneVehClick(v, w)) + return; +} + static void TrainDepotWndProc(Window *w, WindowEvent *e) { switch(e->event) { @@ -590,17 +642,51 @@ case WE_CLICK: { switch(e->click.widget) { case 8: + ResetObjectToPlace(); ShowBuildTrainWindow(w->window_number); break; - case 9: + case 10: + ResetObjectToPlace(); ScrollMainWindowToTile(w->window_number); break; case 6: TrainDepotClickTrain(w, e->click.pt.x, e->click.pt.y); break; + case 9: /* clone button */ + InvalidateWidget(w, 9); + TOGGLEBIT(w->click_state, 9); + + if (HASBIT(w->click_state, 9)) { + _place_clicked_vehicle = NULL; + SetObjectToPlaceWnd(SPR_CURSOR_CLONE, VHM_RECT, w); + } else { + ResetObjectToPlace(); + } + break; + + } + } break; + + case WE_PLACE_OBJ: { + ClonePlaceObj(e->place.tile, w); + } break; + + case WE_ABORT_PLACE_OBJ: { + CLRBIT(w->click_state, 9); + InvalidateWidget(w, 9); + } break; + + // check if a vehicle in a depot was clicked.. + case WE_MOUSELOOP: { + Vehicle *v = _place_clicked_vehicle; + // since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button + if (v != NULL && HASBIT(w->click_state, 9)) { + _place_clicked_vehicle = NULL; + HandleCloneVehClick( v, w); } } break; + case WE_DESTROY: DeleteWindowById(WC_BUILD_VEHICLE, w->window_number); break; @@ -680,10 +766,14 @@ { WWT_MATRIX, RESIZE_RB, 14, 0, 325, 14, 97, 0x601, STR_883F_TRAINS_CLICK_ON_TRAIN_FOR}, { WWT_SCROLLBAR, RESIZE_LRB, 14, 349, 360, 14, 109, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, -{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 167, 110, 121, STR_8815_NEW_VEHICLES, STR_8840_BUILD_NEW_TRAIN_VEHICLE}, -{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 168, 348, 110, 121, STR_00E4_LOCATION, STR_8842_CENTER_MAIN_VIEW_ON_TRAIN}, +{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 116, 110, 121, STR_8815_NEW_VEHICLES, STR_8840_BUILD_NEW_TRAIN_VEHICLE}, +{WWT_NODISTXTBTN, RESIZE_TB, 14, 117, 232, 110, 121, STR_CLONE_TRAIN, STR_CLONE_TRAIN_DEPOT_INFO}, +{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 233, 348, 110, 121, STR_00E4_LOCATION, STR_8842_CENTER_MAIN_VIEW_ON_TRAIN}, + + { WWT_HSCROLLBAR, RESIZE_RTB, 14, 0, 325, 98, 109, 0x0, STR_HSCROLL_BAR_SCROLLS_LIST}, { WWT_PANEL, RESIZE_RTB, 14, 349, 348, 110, 121, 0x0, STR_NULL}, + { WWT_RESIZEBOX, RESIZE_LRTB, 14, 349, 360, 110, 121, 0x0, STR_RESIZE_BUTTON}, { WIDGETS_END}, }; @@ -803,6 +893,7 @@ { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 86, 103, 0x2B2, STR_8847_SHOW_TRAIN_S_ORDERS }, { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 104, 121, 0x2B3, STR_884C_SHOW_TRAIN_DETAILS }, { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 68, 85, 0x2B4, STR_RAIL_REFIT_VEHICLE_TO_CARRY }, +{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 32, 49, SPR_CLONE_TRAIN, STR_CLONE_TRAIN_INFO }, { WWT_PANEL, RESIZE_LRB, 14, 232, 249, 122, 121, 0x0, STR_NULL }, { WWT_RESIZEBOX, RESIZE_LRTB, 14, 238, 249, 122, 133, 0x0, STR_NULL }, { WIDGETS_END } @@ -833,7 +924,7 @@ /* draw widgets & caption */ SetDParam(0, v->string_id); - SetDParam(1, v->unitnumber); + SetDParam(1, v->unitnumber); DrawWindowWidgets(w); if (v->u.rail.crash_anim_pos != 0) { @@ -920,6 +1011,9 @@ case 12: ShowRailVehicleRefitWindow(v); break; + case 13: + DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, NULL, CMD_CLONE_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE)); + break; } } break; @@ -942,7 +1036,7 @@ v = GetVehicle(w->window_number); assert(v->type == VEH_Train); - h = CheckTrainStoppedInDepot(v) >= 0 ? (1 << 9) : (1 << 12); + h = CheckTrainStoppedInDepot(v) >= 0 ? (1 << 9)| (1 << 7) : (1 << 12) | (1 << 13); if (h != w->hidden_state) { w->hidden_state = h; SetWindowDirty(w);
--- a/vehicle.c +++ b/vehicle.c @@ -21,6 +21,7 @@ #include "vehicle_gui.h" #include "depot.h" #include "station.h" +#include "gui.h" #include "rail.h" #define INVALID_COORD (-0x8000) @@ -1669,6 +1670,122 @@ _current_player = OWNER_NONE; } +int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 veh1_veh2, uint32 mode); +int32 CmdMoveRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2); +int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2); +int32 CmdBuildRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2); +int32 CmdBuildShip(int x, int y, uint32 flags, uint32 p1, uint32 p2); +int32 CmdBuildAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2); + + +typedef int32 VehBuildProc(int x, int y, uint32 flags, uint32 p1, uint32 p2); + +static VehBuildProc * const _veh_build_proc_table[] = { + CmdBuildRailVehicle, + CmdBuildRoadVeh, + CmdBuildShip, + CmdBuildAircraft, +}; + +static VehicleID * _new_vehicle_id_proc_table[] = { + &_new_train_id, + &_new_roadveh_id, + &_new_ship_id, + &_new_aircraft_id, +}; + +/** Clone a vehicle. If it is a train, it will clone all the cars too + * @param x,y unused + * @param p1 the original vehicle's index + * @param p2 1 = shared orders, else copied orders + */ +int32 CmdCloneVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) +{ + Vehicle *vfront, *v; + Vehicle *wfront, *w1, *w2; + int cost, total_cost; + VehBuildProc *proc; + VehicleID *new_id; + uint refit_command = 0; + byte needs_refitting = 255; + + if (!IsVehicleIndex(p1)) + return CMD_ERROR; + v = GetVehicle(p1); + wfront = v; + w1 = v; + vfront = v; + + if (!CheckOwnership(v->owner)) + return CMD_ERROR; + + if (v->type == VEH_Train && v->subtype != TS_Front_Engine) return CMD_ERROR; + + //no need to check if it is a depot since the build command do that + switch (v->type) { + case VEH_Train: refit_command = CMD_REFIT_RAIL_VEHICLE; break; + case VEH_Road: break; + case VEH_Ship: refit_command = CMD_REFIT_SHIP; break; + case VEH_Aircraft: refit_command = CMD_REFIT_AIRCRAFT; break; + default: return CMD_ERROR; + } + + proc = _veh_build_proc_table[v->type - VEH_Train]; + new_id = _new_vehicle_id_proc_table[v->type - VEH_Train]; + total_cost = proc(x, y, flags, v->engine_type, 1); + if (total_cost == CMD_ERROR) + return CMD_ERROR; + + if (flags & DC_EXEC) { + wfront = GetVehicle(*new_id); + w1 = wfront; + CmdCloneOrder(x, y, flags, (v->index << 16) | w1->index, p2 & 1 ? CO_SHARE : CO_COPY); + + if (wfront->cargo_type != v->cargo_type) { + //a refit is needed + needs_refitting = v->cargo_type; + } + } + if (v->type == VEH_Train) { + // now we handle the cars + v = v->next; + while (v != NULL) { + cost = proc(x, y, flags, v->engine_type, 1); + if (cost == CMD_ERROR) + return CMD_ERROR; + total_cost += cost; + + if (flags & DC_EXEC) { + // add this unit to the end of the train + w2 = GetVehicle(RailVehInfo(v->engine_type)->flags & RVI_WAGON ? _new_wagon_id : _new_train_id); + CmdMoveRailVehicle(x, y, flags, (w1->index << 16) | w2->index, 0); + w1 = w2; + } + v = v->next; + } + + if (flags & DC_EXEC) { + _new_train_id = wfront->index; + v = vfront; + w1 = wfront; + while (w1 != NULL && v != NULL) { + w1->spritenum = v->spritenum; // makes sure that multiheaded engines are facing the correct way + if (w1->cargo_type != v->cargo_type) // checks if a refit is needed + needs_refitting = v->cargo_type; + w1 = w1->next; + v = v->next; + } + + } + } + if (flags && DC_EXEC && needs_refitting != 255 && v->type != VEH_Road) { // right now we do not refit road vehicles + if (DoCommandByTile(wfront->tile, wfront->index, needs_refitting, 0, refit_command) != CMD_ERROR) + DoCommandByTile(wfront->tile, wfront->index, needs_refitting, DC_EXEC, refit_command); + } + return total_cost; +} + + /** Give a custom name to your vehicle * @param x,y unused * @param p1 vehicle ID to name