mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-06 06:15:04 +00:00
(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
This commit is contained in:
parent
50e41dc1d1
commit
546c34f2e5
@ -332,7 +332,7 @@ bool IsAircraftHangarTile(TileIndex tile)
|
||||
(_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;
|
||||
|
110
aircraft_gui.c
110
aircraft_gui.c
@ -89,6 +89,15 @@ void CcBuildAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2)
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ static const Widget _aircraft_view_widgets[] = {
|
||||
{ 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 @@ static void AircraftViewWndProc(Window *w, WindowEvent *e)
|
||||
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 @@ static void AircraftViewWndProc(Window *w, WindowEvent *e)
|
||||
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 @@ static void DrawAircraftDepotWindow(Window *w)
|
||||
|
||||
/* 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 @@ static void AircraftDepotClickAircraft(Window *w, int x, int y)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ static void AircraftDepotWndProc(Window *w, WindowEvent *e)
|
||||
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 @@ static const Widget _aircraft_depot_widgets[] = {
|
||||
|
||||
{ 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},
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
/* aircraft_gui.c */
|
||||
CommandCallback CcBuildAircraft;
|
||||
CommandCallback CcCloneAircraft;
|
||||
|
||||
/* airport_gui.c */
|
||||
CommandCallback CcBuildAirport;
|
||||
@ -41,13 +42,16 @@ CommandCallback CcRoadDepot;
|
||||
|
||||
/* 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 @@ CommandCallback *_callback_table[] = {
|
||||
/* 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);
|
||||
|
@ -159,6 +159,9 @@ DEF_COMMAND(CmdRemoveSignalTrack);
|
||||
|
||||
DEF_COMMAND(CmdReplaceVehicle);
|
||||
|
||||
DEF_COMMAND(CmdCloneVehicle);
|
||||
|
||||
|
||||
/* The master command table */
|
||||
static const Command _command_proc_table[] = {
|
||||
{CmdBuildRailroadTrack, 0}, /* 0 */
|
||||
@ -300,6 +303,7 @@ static const Command _command_proc_table[] = {
|
||||
{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 */
|
||||
|
@ -136,6 +136,9 @@ enum {
|
||||
CMD_CHANGE_PATCH_SETTING = 114,
|
||||
|
||||
CMD_REPLACE_VEHICLE = 115,
|
||||
|
||||
CMD_CLONE_VEHICLE = 116,
|
||||
|
||||
};
|
||||
|
||||
enum {
|
||||
|
BIN
data/openttd.grf
BIN
data/openttd.grf
Binary file not shown.
@ -2404,6 +2404,12 @@ STR_881C_NEW_RAIL_VEHICLES :{WHITE}New Rail
|
||||
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_9806_CAN_T_BUILD_SHIPS :{WHITE}Can't bu
|
||||
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_A000_AIRPORTS :{WHITE}Airports
|
||||
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
|
||||
|
110
roadveh_gui.c
110
roadveh_gui.c
@ -230,6 +230,16 @@ static void ShowRoadVehDetailsWindow(Vehicle *v)
|
||||
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 @@ static void RoadVehViewWndProc(Window *w, WindowEvent *e)
|
||||
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 @@ static void RoadVehViewWndProc(Window *w, WindowEvent *e)
|
||||
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 @@ static const Widget _roadveh_view_widgets[] = {
|
||||
{ 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 @@ static void DrawRoadDepotWindow(Window *w)
|
||||
|
||||
/* 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 @@ static void RoadDepotClickVeh(Window *w, int x, int y)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ static void RoadDepotWndProc(Window *w, WindowEvent *e)
|
||||
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 @@ static const Widget _road_depot_widgets[] = {
|
||||
|
||||
{ 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},
|
||||
|
259
ship_gui.c
259
ship_gui.c
@ -320,6 +320,15 @@ void CcBuildShip(bool success, TileIndex tile, uint32 p1, uint32 p2)
|
||||
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 ShowBuildShipWindow(TileIndex tile)
|
||||
|
||||
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 @@ static void ShipViewWndProc(Window *w, WindowEvent *e) {
|
||||
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));
|
||||
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 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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -578,6 +605,7 @@ static const Widget _ship_view_widgets[] = {
|
||||
{ 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 @@ static void ShipDepotClick(Window *w, int x, int y)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ static void ShipDepotWndProc(Window *w, WindowEvent *e) {
|
||||
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 @@ static const Widget _ship_depot_widgets[] = {
|
||||
|
||||
{ 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},
|
||||
|
@ -732,7 +732,7 @@ static const char * const _cached_filenames[4] = {
|
||||
"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
|
||||
|
@ -64,6 +64,11 @@ enum Sprites {
|
||||
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 @@ typedef enum CursorSprites {
|
||||
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[])
|
||||
|
38
train_cmd.c
38
train_cmd.c
@ -568,7 +568,7 @@ void AddRearEngineToMultiheadedTrain(Vehicle *v, Vehicle *u, bool building)
|
||||
/** 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 @@ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||
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 @@ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||
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 @@ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||
|
||||
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 @@ int32 CmdForceTrainProceed(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||
/** 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 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||
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 @@ int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||
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 @@ int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
|
||||
|
106
train_gui.c
106
train_gui.c
@ -154,6 +154,17 @@ void CcBuildLoco(bool success, TileIndex tile, uint32 p1, uint32 p2)
|
||||
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 @@ static void DrawTrainDepotWindow(Window *w)
|
||||
|
||||
/* 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 @@ static void TrainDepotClickTrain(Window *w, int x, int y)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ static void TrainDepotWndProc(Window *w, WindowEvent *e)
|
||||
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 @@ static const Widget _train_depot_widgets[] = {
|
||||
|
||||
{ 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 @@ static Widget _train_view_widgets[] = {
|
||||
{ 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 @@ static void TrainViewWndProc(Window *w, WindowEvent *e)
|
||||
|
||||
/* 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 @@ static void TrainViewWndProc(Window *w, WindowEvent *e)
|
||||
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 @@ static void TrainViewWndProc(Window *w, WindowEvent *e)
|
||||
|
||||
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);
|
||||
|
117
vehicle.c
117
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 @@ void MaybeReplaceVehicle(Vehicle *v)
|
||||
_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
|
||||
|
Loading…
Reference in New Issue
Block a user