(svn r1323) Adding autoreplace feature

This feature works much like autorenew, but it will get you a new engine type instead of a new one of the same type. Once 
ordered, it will automatically replace the engines while they visits a depot. The GUI for setting this up have been added on the 
vehicle overview windows
Note: autorenew is now autoreplace, but to the same engine type
Nice new features, that was added to make this possible
- windows can now have two independant vertical scrollbars
- CMD_SHOW_NO_ERROR have been added as a flag for DoCommandP. It will make it do the action instead of showing the red box with 
estimated costs even if shift is pressed
- fixed problem where enginetypes where not initialized when loading a game. It's now done in InitializeGame()
This commit is contained in:
bjarni 2005-01-02 17:23:04 +00:00
parent a11f46fed4
commit 29d8c5bb50
27 changed files with 1247 additions and 270 deletions

View File

@ -406,29 +406,32 @@ int32 CmdChangeAircraftServiceInt(int x, int y, uint32 flags, uint32 p1, uint32
}
// p1 = vehicle
// p2 = new cargo type
// p2 = new cargo type(0xFF)
// p2 = skip check for stopped in hanger (0x0100)
int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v,*u;
int pass, mail;
int32 cost;
byte SkipStoppedInHangerCheck = (p2 & 0x100) >> 8; //excludes the cargo value
byte new_cargo_type = p2 & 0xFF; //gets the cargo number
SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_RUN);
v = &_vehicles[p1];
if (!CheckOwnership(v->owner) || !CheckStoppedInHangar(v))
if (!CheckOwnership(v->owner) || (!CheckStoppedInHangar(v) && !(SkipStoppedInHangerCheck)))
return CMD_ERROR;
pass = AircraftVehInfo(v->engine_type)->passanger_capacity;
if (p2 != 0) {
if (new_cargo_type != CT_PASSENGERS) {
pass >>= 1;
if (p2 != 5)
if (new_cargo_type != CT_GOODS)
pass >>= 1;
}
_aircraft_refit_capacity = pass;
cost = 0;
if (IS_HUMAN_PLAYER(v->owner) && (byte)p2 != v->cargo_type) {
if (IS_HUMAN_PLAYER(v->owner) && new_cargo_type != v->cargo_type) {
cost = _price.aircraft_base >> 7;
}
@ -437,12 +440,15 @@ int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
u = v->next;
mail = AircraftVehInfo(v->engine_type)->mail_capacity;
if (p2 != 0) {
if (new_cargo_type != CT_PASSENGERS) {
mail = 0;
}
u->cargo_cap = mail;
v->cargo_count = u->cargo_count = 0;
v->cargo_type = (byte)p2;
//autorefitted planes wants to keep the cargo
//it will be checked if the cargo is valid in CmdReplaceVehicle
if (!(SkipStoppedInHangerCheck))
v->cargo_count = u->cargo_count = 0;
v->cargo_type = new_cargo_type;
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
}
@ -1157,7 +1163,7 @@ static void AircraftEnterHangar(Vehicle *v)
ServiceAircraft(v);
MaybeRenewVehicle(v);
MaybeReplaceVehicle(v);
TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);

View File

@ -13,6 +13,26 @@
#include "player.h"
void Set_DPARAM_Aircraft_Build_Window(uint16 engine_number)
{
const AircraftVehicleInfo *avi = AircraftVehInfo(engine_number);
Engine *e;
YearMonthDay ymd;
SetDParam(0, avi->base_cost * (_price.aircraft_base>>3)>>5);
SetDParam(1, avi->max_speed * 8);
SetDParam(2, avi->passanger_capacity);
SetDParam(3, avi->mail_capacity);
SetDParam(4, avi->running_cost * _price.aircraft_running >> 8);
e = &_engines[engine_number];
SetDParam(6, e->lifelength);
SetDParam(7, e->reliability * 100 >> 16);
ConvertDayToYMD(&ymd, e->intro_date);
SetDParam(5, ymd.year + 1920);
}
static void DrawAircraftImage(Vehicle *v, int x, int y, VehicleID selection)
{
int image = GetAircraftImage(v, 6);
@ -43,8 +63,6 @@ void CcBuildAircraft(bool success, uint tile, uint32 p1, uint32 p2)
static void NewAircraftWndProc(Window *w, WindowEvent *e)
{
YearMonthDay ymd;
switch(e->event) {
case WE_PAINT: {
@ -89,20 +107,7 @@ static void NewAircraftWndProc(Window *w, WindowEvent *e)
WP(w,buildtrain_d).sel_engine = selected_id;
if (selected_id != -1) {
const AircraftVehicleInfo *avi = AircraftVehInfo(selected_id);
Engine *e;
SetDParam(0, avi->base_cost * (_price.aircraft_base>>3)>>5);
SetDParam(1, avi->max_speed * 8);
SetDParam(2, avi->passanger_capacity);
SetDParam(3, avi->mail_capacity);
SetDParam(4, avi->running_cost * _price.aircraft_running >> 8);
e = &_engines[selected_id];
SetDParam(6, e->lifelength);
SetDParam(7, e->reliability * 100 >> 16);
ConvertDayToYMD(&ymd, e->intro_date);
SetDParam(5, ymd.year + 1920);
Set_DPARAM_Aircraft_Build_Window(selected_id);
DrawString(2, 111, STR_A007_COST_SPEED_CAPACITY_PASSENGERS, 0);
}
@ -899,7 +904,7 @@ static Widget _player_aircraft_widgets[] = {
{ WWT_MATRIX, 14, 0, 248, 26, 169, 0x401, STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT},
{ WWT_SCROLLBAR, 14, 249, 259, 26, 169, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_PUSHTXTBTN, 14, 0, 129, 170, 181, STR_A003_NEW_AIRCRAFT, STR_A020_BUILD_NEW_AIRCRAFT_REQUIRES},
{ WWT_PANEL, 14, 130, 259, 170, 181, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, 14, 130, 259, 170, 181, STR_REPLACE_VEHICLES, STR_REPLACE_HELP},
{ WIDGETS_END},
};
@ -1005,7 +1010,7 @@ static void PlayerAircraftWndProc(Window *w, WindowEvent *e)
break;
case 4: case 5:/* Select sorting criteria dropdown menu */
ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0);
ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0, 0);
return;
case 7: { /* Matrix to show vehicles */
@ -1044,6 +1049,11 @@ static void PlayerAircraftWndProc(Window *w, WindowEvent *e)
ShowBuildAircraftWindow(0);
} break;
case 10:
ShowReplaceVehicleWindow(VEH_Aircraft);
break;
}
} break;

View File

@ -167,7 +167,7 @@ DEF_COMMAND(CmdStartScenario);
DEF_COMMAND(CmdBuildManySignals);
DEF_COMMAND(CmdRenewVehicle);
DEF_COMMAND(CmdReplaceVehicle);
/* The master command table */
static CommandProc * const _command_proc_table[] = {
@ -309,7 +309,7 @@ static CommandProc * const _command_proc_table[] = {
CmdDestroyCompanyHQ, /* 111 */
CmdGiveMoney, /* 112 */
CmdChangePatchSetting, /* 113 */
CmdRenewVehicle, /* 114 */
CmdReplaceVehicle, /* 114 */
};
int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
@ -431,7 +431,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
_docommand_recursive = 1;
// cost estimation only?
if (_shift_pressed && _current_player == _local_player && !(cmd & CMD_NETWORK_COMMAND)) {
if (_shift_pressed && _current_player == _local_player && !(cmd & (CMD_NETWORK_COMMAND | CMD_SHOW_NO_ERROR))) {
// estimate the cost.
res = proc(x, y, flags, p1, p2);
if ((uint32)res >> 16 == 0x8000) {

View File

@ -149,7 +149,7 @@ enum {
CMD_GIVE_MONEY = 112,
CMD_CHANGE_PATCH_SETTING = 113,
CMD_RENEW_VEHICLE = 114,
CMD_REPLACE_VEHICLE = 114,
};
enum {
@ -172,6 +172,7 @@ enum {
CMD_NO_WATER = 0x400,
CMD_NETWORK_COMMAND = 0x800, // execute the command without sending it on the network
CMD_NO_TEST_IF_IN_NETWORK = 0x1000, // When enabled, the command will bypass the no-DC_EXEC round if in network
CMD_SHOW_NO_ERROR = 0x2000,
};
//#define return_cmd_error(errcode) do { _error_message=(errcode); return CMD_ERROR; } while(0)

View File

@ -115,6 +115,29 @@ static void CalcEngineReliability(Engine *e)
}
}
void AddTypeToEngines()
{
Engine *e;
uint32 counter = 0;
for(e=_engines; e != endof(_engines); e++, counter++) {
e->type = VEH_Train;
if (counter >= ROAD_ENGINES_INDEX) {
e->type = VEH_Road;
if (counter >= SHIP_ENGINES_INDEX) {
e->type = VEH_Ship;
if (counter >= AIRCRAFT_ENGINES_INDEX) {
e->type = VEH_Aircraft;
if (counter >= TOTAL_NUM_ENGINES) {
e->type = VEH_Special;
}
}
}
}
}
}
void StartupEngines()
{
Engine *e;
@ -123,8 +146,8 @@ void StartupEngines()
SetupEngineNames();
for(e=_engines, ei=_engine_info; e != endof(_engines); e++, ei++, counter++) {
e->age = 0;
e->railtype = ei->railtype_climates >> 4;
e->flags = 0;
@ -170,19 +193,6 @@ void StartupEngines()
It should hopefully be the same as when you ask a vehicle what it is
but using this, you can ask what type an engine number is
even if it is not a vehicle (yet)*/
e->type = VEH_Train;
if (counter >= ROAD_ENGINES_INDEX) {
e->type = VEH_Road;
if (counter >= SHIP_ENGINES_INDEX) {
e->type = VEH_Ship;
if (counter >= AIRCRAFT_ENGINES_INDEX) {
e->type = VEH_Aircraft;
if (counter >= TOTAL_NUM_ENGINES) {
e->type = VEH_Special;
}
}
}
}
}
AdjustAvailAircraft();

View File

@ -80,6 +80,7 @@ enum {
};
void AddTypeToEngines();
void StartupEngines();

1
gui.h
View File

@ -85,6 +85,7 @@ void CheckRedrawStationCoverage(Window *w);
void ShowSmallMap();
void ShowExtraViewPortWindow();
void SetVScrollCount(Window *w, int num);
void SetVScroll2Count(Window *w, int num);
void SetHScrollCount(Window *w, int num);
int HandleEditBoxKey(Window *w, int wid, WindowEvent *we);

View File

@ -2763,3 +2763,25 @@ STR_SCHEDULED_TRAINS_TIP :{BLACK}Show all trains which have this station on
STR_SCHEDULED_ROAD_VEHICLES_TIP :{BLACK}Show all road vehicles which have this station on their schedule
STR_SCHEDULED_AIRCRAFT_TIP :{BLACK}Show all aircraft which have this station on their schedule
STR_SCHEDULED_SHIPS_TIP :{BLACK}Show all ships which have this station on their schedule
STR_REPLACE_VEHICLES :{BLACK}Replace Vehicles
STR_REPLACE_VEHICLES_START :{BLACK}Start Replacing Vehicles
STR_REPLACE_VEHICLES_STOP :{BLACK}Stop Replaing Vehicles
STR_NOT_REPLACING :{BLACK}Not replacing
STR_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}No vehicle selected
STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Select a type of engine to replace{}Select an engine on the right side to replace to
STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Select an engine to replace to{}It will replace the engines selected on the left side
STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Press this button if you don't want to replace the engine, you selected on the left
STR_REPLACE_HELP_START_BUTTON :{BLACK}Press this button if you want to replace the engine selected on the left with the one selected on the right
STR_REPLACE_HELP_RAILTYPE :{BLACK}Select a railtype you want to select engines for
STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}This displays what engine the selected engine on the left are being replaced to
STR_REPLACE_HELP :{BLACK}This feature allows you to select an enginetype and replace that one with another one. This will then be done automatically when the vehicles enters a depot anyway
############ Lists rail types
STR_RAIL_VEHICLES :{BLACK}Rail Vehicles
STR_MONORAIL_VEHICLES :{BLACK}Monorail Vehicles
STR_MAGLEV_VEHICLES :{BLACK}Maglev Vehicles
############ End of list of rail types

8
misc.c
View File

@ -9,6 +9,7 @@
#include "network.h"
#include "network_data.h"
#include "network_server.h"
#include "engine.h"
extern void StartupEconomy();
extern void InitNewsItemStructs();
@ -182,6 +183,13 @@ void ConvertGroundTilesIntoWaterTiles();
void InitializeGame()
{
// Initialize the autoreplace array. Needs to be cleared between each game
int i;
for (i = 0; i < 256; i++) {
_autoreplace_array[i] = i;
}
AddTypeToEngines(); // make sure all engines have a type
SetObjectToPlace(1, 0, 0, 0);
_pause = 0;

View File

@ -692,6 +692,14 @@ void SetVScrollCount(Window *w, int num)
if (num < w->vscroll.pos) w->vscroll.pos = num;
}
void SetVScroll2Count(Window *w, int num)
{
w->vscroll2.count = num;
num -= w->vscroll2.cap;
if (num < 0) num = 0;
if (num < w->vscroll2.pos) w->vscroll2.pos = num;
}
void SetHScrollCount(Window *w, int num)
{
w->hscroll.count = num;
@ -700,7 +708,6 @@ void SetHScrollCount(Window *w, int num)
if (num < w->hscroll.pos) w->hscroll.pos = num;
}
int HandleEditBoxKey(Window *w, int wid, WindowEvent *we)
{
byte *p;

View File

@ -231,7 +231,7 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
DeleteWindowById(WC_NETWORK_WINDOW, 0);
break;
case 4: case 5:
ShowDropDownMenu(w, _lan_internet_types_dropdown, _network_lan_internet, 5, 0); // do it for widget 5
ShowDropDownMenu(w, _lan_internet_types_dropdown, _network_lan_internet, 5, 0, 0); // do it for widget 5
break;
case 10: { /* Matrix to show networkgames */
uint32 id_v = (e->click.pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW;
@ -540,13 +540,13 @@ static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
SetWindowDirty(w);
} break;
case 7: case 8: /* Connection type */
ShowDropDownMenu(w, _connection_types_dropdown, _network_advertise, 8, 0); // do it for widget 8
ShowDropDownMenu(w, _connection_types_dropdown, _network_advertise, 8, 0, 0); // do it for widget 8
break;
case 9: case 10: /* Number of Players */
ShowDropDownMenu(w, _players_dropdown, _network_game_info.clients_max - 2, 10, 0); // do it for widget 10
ShowDropDownMenu(w, _players_dropdown, _network_game_info.clients_max - 2, 10, 0, 0); // do it for widget 10
return;
case 11: case 12: /* Language */
ShowDropDownMenu(w, _language_dropdown, _network_game_info.server_lang, 12, 0); // do it for widget 12
ShowDropDownMenu(w, _language_dropdown, _network_game_info.server_lang, 12, 0, 0); // do it for widget 12
return;
case 13: /* Start game */
_is_network_server = true;

View File

@ -105,6 +105,8 @@ int32 EstimateRoadVehCost(byte engine_type)
return ((_price.roadveh_base >> 3) * RoadVehInfo(engine_type)->base_cost) >> 5;
}
// p1 = engine_type
// p2 not used
int32 CmdBuildRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
int32 cost;
@ -211,6 +213,8 @@ int32 CmdStartStopRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return 0;
}
// p1 = vehicle index in &_vehicles[]
// p2 not used
int32 CmdSellRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v;
@ -1379,7 +1383,7 @@ void RoadVehEnterDepot(Vehicle *v)
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
MaybeRenewVehicle(v);
MaybeReplaceVehicle(v);
VehicleServiceInDepot(v);

View File

@ -12,6 +12,25 @@
#include "player.h"
#include "engine.h"
void Set_DPARAM_Road_Veh_Build_Window(uint16 engine_number)
{
const RoadVehicleInfo *rvi = RoadVehInfo(engine_number);
Engine *e;
YearMonthDay ymd;
SetDParam(0, rvi->base_cost * (_price.roadveh_base>>3)>>5);
SetDParam(1, rvi->max_speed * 10 >> 5);
SetDParam(2, rvi->running_cost * _price.roadveh_running >> 8);
SetDParam(4, rvi->capacity);
SetDParam(3, _cargoc.names_long_p[rvi->cargo_type]);
e = &_engines[engine_number];
SetDParam(6, e->lifelength);
SetDParam(7, e->reliability * 100 >> 16);
ConvertDayToYMD(&ymd, e->intro_date);
SetDParam(5, ymd.year + 1920);
}
static void DrawRoadVehImage(Vehicle *v, int x, int y, VehicleID selection)
{
int image = GetRoadVehImage(v, 6);
@ -307,8 +326,6 @@ void ShowRoadVehViewWindow(Vehicle *v)
static void DrawNewRoadVehWindow(Window *w)
{
YearMonthDay ymd;
if (w->window_number == 0)
w->disabled_state = 1 << 5;
@ -350,20 +367,7 @@ static void DrawNewRoadVehWindow(Window *w)
WP(w,buildtrain_d).sel_engine = selected_id;
if (selected_id != -1) {
const RoadVehicleInfo *rvi = RoadVehInfo(selected_id);
Engine *e;
SetDParam(0, rvi->base_cost * (_price.roadveh_base>>3)>>5);
SetDParam(1, rvi->max_speed * 10 >> 5);
SetDParam(2, rvi->running_cost * _price.roadveh_running >> 8);
SetDParam(4, rvi->capacity);
SetDParam(3, _cargoc.names_long_p[rvi->cargo_type]);
e = &_engines[selected_id];
SetDParam(6, e->lifelength);
SetDParam(7, e->reliability * 100 >> 16);
ConvertDayToYMD(&ymd, e->intro_date);
SetDParam(5, ymd.year + 1920);
Set_DPARAM_Road_Veh_Build_Window(selected_id);
DrawString(2, 127, STR_9008_COST_SPEED_RUNNING_COST, 0);
}
@ -714,7 +718,7 @@ static Widget _player_roadveh_widgets[] = {
{ WWT_SCROLLBAR, 14, 249, 259, 26, 207, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
/* only for our road list, a 'Build Vehicle' button that opens the depot of the last built depot */
{ WWT_PUSHTXTBTN, 14, 0, 129, 208, 219, STR_8815_NEW_VEHICLES, STR_901B_BUILD_NEW_ROAD_VEHICLES},
{ WWT_PANEL, 14, 130, 259, 208, 219, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, 14, 130, 259, 208, 219, STR_REPLACE_VEHICLES, STR_REPLACE_HELP},
{ WIDGETS_END},
};
@ -818,7 +822,7 @@ static void PlayerRoadVehWndProc(Window *w, WindowEvent *e)
break;
case 4: case 5:/* Select sorting criteria dropdown menu */
ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0);
ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0, 0);
return;
case 7: { /* Matrix to show vehicles */
uint32 id_v = (e->click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / PLY_WND_PRC__SIZE_OF_ROW_SMALL;
@ -856,6 +860,10 @@ static void PlayerRoadVehWndProc(Window *w, WindowEvent *e)
ShowBuildRoadVehWindow(0);
} break;
case 10: {
ShowReplaceVehicleWindow(VEH_Road);
break;
}
}
} break;

View File

@ -92,35 +92,35 @@ static void GameOptionsWndProc(Window *w, WindowEvent *e)
case WE_CLICK:
switch(e->click.widget) {
case 5:
ShowDropDownMenu(w, _currency_string_list, _opt_mod_ptr->currency, e->click.widget, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies());
ShowDropDownMenu(w, _currency_string_list, _opt_mod_ptr->currency, e->click.widget, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);
return;
case 8:
ShowDropDownMenu(w, _distances_dropdown, _opt_mod_ptr->kilometers, e->click.widget, 0);
ShowDropDownMenu(w, _distances_dropdown, _opt_mod_ptr->kilometers, e->click.widget, 0, 0);
return;
case 11: {
int i = _opt_mod_ptr->road_side;
ShowDropDownMenu(w, _driveside_dropdown, i, e->click.widget, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i));
ShowDropDownMenu(w, _driveside_dropdown, i, e->click.widget, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i), 0);
return;
}
case 14: {
int i = _opt_mod_ptr->town_name;
ShowDropDownMenu(w, BuildDynamicDropdown(STR_TOWNNAME_ORIGINAL_ENGLISH, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1), i, e->click.widget, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i));
ShowDropDownMenu(w, BuildDynamicDropdown(STR_TOWNNAME_ORIGINAL_ENGLISH, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1), i, e->click.widget, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i), 0);
return;
}
case 17:
ShowDropDownMenu(w, _autosave_dropdown, _opt_mod_ptr->autosave, e->click.widget, 0);
ShowDropDownMenu(w, _autosave_dropdown, _opt_mod_ptr->autosave, e->click.widget, 0, 0);
return;
case 20:
ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names&1)?1:0, e->click.widget, (_vehicle_design_names&2)?0:2);
ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names&1)?1:0, e->click.widget, (_vehicle_design_names&2)?0:2, 0);
return;
case 21:
return;
case 24:
ShowDropDownMenu(w, _dynlang.dropdown, _dynlang.curr, e->click.widget, 0);
ShowDropDownMenu(w, _dynlang.dropdown, _dynlang.curr, e->click.widget, 0, 0);
return;
case 27:
// setup resolution dropdown
ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), e->click.widget, 0);
ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), e->click.widget, 0, 0);
return;
case 28: /* Click fullscreen on/off */
(_fullscreen) ? CLRBIT(w->click_state, 28) : SETBIT(w->click_state, 28);
@ -128,7 +128,7 @@ static void GameOptionsWndProc(Window *w, WindowEvent *e)
SetWindowDirty(w);
return;
case 31: /* Setup screenshot format dropdown */
ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, e->click.widget, 0);
ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, e->click.widget, 0, 0);
return;
}

View File

@ -400,7 +400,7 @@ static void ShipEnterDepot(Vehicle *v)
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
MaybeRenewVehicle(v);
MaybeReplaceVehicle(v);
TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
@ -975,30 +975,38 @@ int32 CmdChangeShipServiceInt(int x, int y, uint32 flags, uint32 p1, uint32 p2)
// p1 = vehicle
// p2 = new cargo
// p2 = new cargo (0xFF)
// p2 = skip check for stopped in hanger (0x0100)
int32 CmdRefitShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v;
int32 cost;
byte SkipStoppedInDepotCheck = (p2 & 0x100) >> 8; //excludes the cargo value
p2 = p2 & 0xFF;
SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
v = &_vehicles[p1];
if (!CheckOwnership(v->owner))
return CMD_ERROR;
if (!IsShipDepotTile(v->tile) ||
!(v->vehstatus&VS_STOPPED) ||
v->u.ship.state != 0x80)
return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
if (!( SkipStoppedInDepotCheck )) {
if (!IsShipDepotTile(v->tile) ||
!(v->vehstatus&VS_STOPPED) ||
v->u.ship.state != 0x80)
return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
}
cost = 0;
if (IS_HUMAN_PLAYER(v->owner) && (byte)p2 != v->cargo_type) {
cost = _price.ship_base >> 7;
}
if (flags & DC_EXEC) {
v->cargo_count = 0;
//autorefitted ships wants to keep the cargo
//it will be checked if the cargo is valid in CmdRenewVehicle
if (!(SkipStoppedInDepotCheck))
v->cargo_count = 0;
v->cargo_type = (byte)p2;
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
}

View File

@ -12,6 +12,25 @@
#include "player.h"
#include "engine.h"
void Set_DPARAM_Ship_Build_Window(uint16 engine_number)
{
YearMonthDay ymd;
const ShipVehicleInfo *svi = ShipVehInfo(engine_number);
Engine *e;
SetDParam(0, svi->base_cost * (_price.ship_base>>3)>>5);
SetDParam(1, svi->max_speed * 10 >> 5);
SetDParam(2, _cargoc.names_long_p[svi->cargo_type]);
SetDParam(3, svi->capacity);
SetDParam(4, svi->refittable ? STR_9842_REFITTABLE : STR_EMPTY);
SetDParam(5, svi->running_cost * _price.ship_running >> 8);
e = &_engines[engine_number];
SetDParam(7, e->lifelength);
SetDParam(8, e->reliability * 100 >> 16);
ConvertDayToYMD(&ymd, e->intro_date);
SetDParam(6, ymd.year + 1920);
}
static void DrawShipImage(Vehicle *v, int x, int y, VehicleID selection);
@ -317,7 +336,6 @@ void CcBuildShip(bool success, uint tile, uint32 p1, uint32 p2)
static void NewShipWndProc(Window *w, WindowEvent *e)
{
YearMonthDay ymd;
switch(e->event) {
case WE_PAINT:
if (w->window_number == 0)
@ -362,21 +380,7 @@ static void NewShipWndProc(Window *w, WindowEvent *e)
WP(w,buildtrain_d).sel_engine = selected_id;
if (selected_id != -1) {
const ShipVehicleInfo *svi = ShipVehInfo(selected_id);
Engine *e;
SetDParam(0, svi->base_cost * (_price.ship_base>>3)>>5);
SetDParam(1, svi->max_speed * 10 >> 5);
SetDParam(2, _cargoc.names_long_p[svi->cargo_type]);
SetDParam(3, svi->capacity);
SetDParam(4, svi->refittable ? STR_9842_REFITTABLE : STR_EMPTY);
SetDParam(5, svi->running_cost * _price.ship_running >> 8);
e = &_engines[selected_id];
SetDParam(7, e->lifelength);
SetDParam(8, e->reliability * 100 >> 16);
ConvertDayToYMD(&ymd, e->intro_date);
SetDParam(6, ymd.year + 1920);
Set_DPARAM_Ship_Build_Window(selected_id);
DrawString(2, 111, STR_980A_COST_SPEED_CAPACITY_RUNNING, 0);
}
@ -881,7 +885,7 @@ static Widget _player_ships_widgets[] = {
{ WWT_MATRIX, 14, 0, 248, 26, 169, 0x401, STR_9823_SHIPS_CLICK_ON_SHIP_FOR},
{ WWT_SCROLLBAR, 14, 249, 259, 26, 169, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_PUSHTXTBTN, 14, 0, 129, 170, 181, STR_9804_NEW_SHIPS, STR_9824_BUILD_NEW_SHIPS_REQUIRES},
{ WWT_PANEL, 14, 130, 259, 170, 181, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, 14, 130, 259, 170, 181, STR_REPLACE_VEHICLES, STR_REPLACE_HELP},
{ WIDGETS_END},
};
@ -986,7 +990,7 @@ static void PlayerShipsWndProc(Window *w, WindowEvent *e)
SetWindowDirty(w);
break;
case 4: case 5:/* Select sorting criteria dropdown menu */
ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0);
ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0, 0);
return;
case 7: { /* Matrix to show vehicles */
uint32 id_v = (e->click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / PLY_WND_PRC__SIZE_OF_ROW_BIG;
@ -1024,7 +1028,12 @@ static void PlayerShipsWndProc(Window *w, WindowEvent *e)
ShowBuildShipWindow(0);
} break;
case 10: {
ShowReplaceVehicleWindow(VEH_Ship);
break;
}
}
} break;
case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */

View File

@ -1057,23 +1057,27 @@ int32 CmdForceTrainProceed(int x, int y, uint32 flags, uint32 p1, uint32 p2)
}
// p1 = vehicle to refit
// p2 = new cargo
// p2 = new cargo (0xFF)
// p2 = skip check for stopped in hanger (0x0100)
int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v;
int32 cost;
uint num;
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
byte SkipStoppedInDepotCheck = (p2 & 0x100) >> 8;
p2 = p2 & 0xFF;
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
v = &_vehicles[p1];
if (!CheckOwnership(v->owner) || CheckStoppedInDepot(v) < 0)
if (!CheckOwnership(v->owner) || ((CheckStoppedInDepot(v) < 0) && !(SkipStoppedInDepotCheck)))
return CMD_ERROR;
cost = 0;
num = 0;
do {
/* XXX: We also refit all the attached wagons en-masse if they
* can be refitted. This is how TTDPatch does it. TODO: Have
@ -1084,12 +1088,16 @@ int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
cost += (_price.build_railvehicle >> 8);
num += v->cargo_cap;
if (flags & DC_EXEC) {
v->cargo_count = 0;
//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_type = (byte)p2;
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
}
}
} while ( (v=v->next) != NULL);
// SkipStoppedInDepotCheck is called by CmdReplace and it should only apply to the single car it is called for
} while ( (v=v->next) != NULL || SkipStoppedInDepotCheck );
_returned_refit_amount = num;
@ -2618,7 +2626,7 @@ void TrainEnterDepot(Vehicle *v, uint tile)
v->load_unload_time_rem = 0;
v->cur_speed = 0;
MaybeRenewVehicle(v);
MaybeReplaceVehicle(v);
TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);

View File

@ -16,6 +16,44 @@
int _traininfo_vehicle_pitch = 0;
void Set_DPARAM_Train_Engine_Build_Window(uint16 engine_number)
{
const RailVehicleInfo *rvi = RailVehInfo(engine_number);
Engine *e;
int multihead = (rvi->flags&RVI_MULTIHEAD?1:0);
YearMonthDay ymd;
SetDParam(0, rvi->base_cost * (_price.build_railvehicle >> 3) >> 5);
SetDParam(2, rvi->max_speed * 10 >> 4);
SetDParam(3, rvi->power << multihead);
SetDParam(1, rvi->weight << multihead);
SetDParam(4, (rvi->running_cost_base * _price.running_rail[rvi->engclass] >> 8) << multihead);
SetDParam(5, STR_8838_N_A);
if (rvi->capacity != 0) {
SetDParam(6, rvi->capacity << multihead);
SetDParam(5, _cargoc.names_long_p[rvi->cargo_type]);
}
e = &_engines[engine_number];
SetDParam(8, e->lifelength);
SetDParam(9, e->reliability * 100 >> 16);
ConvertDayToYMD(&ymd, e->intro_date);
SetDParam(7, ymd.year + 1920);
}
void Set_DPARAM_Train_Car_Build_Window(Window *w, uint16 engine_number)
{
const RailVehicleInfo *rvi = RailVehInfo(engine_number);
SetDParam(0, DoCommandByTile(w->window_number, engine_number, 0, DC_QUERY_COST, CMD_BUILD_RAIL_VEHICLE) );
SetDParam(4, rvi->capacity);
SetDParam(1, rvi->weight);
SetDParam(3, _cargoc.names_long_p[rvi->cargo_type]);
SetDParam(2, (_cargoc.weights[rvi->cargo_type] * rvi->capacity >> 4) + rvi->weight);
}
void CcBuildWagon(bool success, uint tile, uint32 p1, uint32 p2)
{
@ -131,43 +169,16 @@ static void NewRailVehicleWndProc(Window *w, WindowEvent *e)
if (selected_id != -1) {
const RailVehicleInfo *rvi = RailVehInfo(selected_id);
Engine *e;
YearMonthDay ymd;
if (!(rvi->flags & RVI_WAGON)) {
/* it's an engine */
int multihead = (rvi->flags&RVI_MULTIHEAD?1:0);
SetDParam(0, rvi->base_cost * (_price.build_railvehicle >> 3) >> 5);
SetDParam(2, rvi->max_speed * 10 >> 4);
SetDParam(3, rvi->power << multihead);
SetDParam(1, rvi->weight << multihead);
SetDParam(4, (rvi->running_cost_base * _price.running_rail[rvi->engclass] >> 8) << multihead);
SetDParam(5, STR_8838_N_A);
if (rvi->capacity != 0) {
SetDParam(6, rvi->capacity << multihead);
SetDParam(5, _cargoc.names_long_p[rvi->cargo_type]);
}
e = &_engines[selected_id];
SetDParam(8, e->lifelength);
SetDParam(9, e->reliability * 100 >> 16);
ConvertDayToYMD(&ymd, e->intro_date);
SetDParam(7, ymd.year + 1920);
Set_DPARAM_Train_Engine_Build_Window(selected_id);
DrawString(2, 0x7F, STR_8817_COST_WEIGHT_T_SPEED_POWER, 0);
} else {
/* it's a wagon */
SetDParam(0,
DoCommandByTile(w->window_number, selected_id, 0, DC_QUERY_COST, CMD_BUILD_RAIL_VEHICLE)
);
SetDParam(4, rvi->capacity);
SetDParam(1, rvi->weight);
SetDParam(3, _cargoc.names_long_p[rvi->cargo_type]);
SetDParam(2, (_cargoc.weights[rvi->cargo_type] * rvi->capacity >> 4) + rvi->weight);
Set_DPARAM_Train_Car_Build_Window(w, selected_id);
DrawString(2, 0x7F, STR_8821_COST_WEIGHT_T_T_CAPACITY, 0);
}
}
@ -1183,7 +1194,7 @@ static Widget _player_trains_widgets[] = {
{ WWT_MATRIX, 14, 0, 313, 26, 207, 0x701, STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
{ WWT_SCROLLBAR, 14, 314, 324, 26, 207, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_PUSHTXTBTN, 14, 0, 161, 208, 219, STR_8815_NEW_VEHICLES, STR_883E_BUILD_NEW_TRAINS_REQUIRES},
{ WWT_PANEL, 14, 162, 324, 208, 219, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, 14, 162, 324, 208, 219, STR_REPLACE_VEHICLES, STR_REPLACE_HELP},
{ WIDGETS_END},
};
@ -1289,7 +1300,7 @@ static void PlayerTrainsWndProc(Window *w, WindowEvent *e)
break;
case 4: case 5:/* Select sorting criteria dropdown menu */
ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0);
ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 5, 0, 0);
return;
case 7: { /* Matrix to show vehicles */
@ -1328,6 +1339,11 @@ static void PlayerTrainsWndProc(Window *w, WindowEvent *e)
ShowBuildTrainWindow(0);
} break;
case 10: {
ShowReplaceVehicleWindow(VEH_Train);
break;
}
}
} break;

1
ttd.h
View File

@ -439,6 +439,7 @@ enum {
WC_CLIENT_LIST = 0x49,
WC_NETWORK_STATUS_WINDOW = 0x4A,
WC_CUSTOM_CURRENCY = 0x4B,
WC_REPLACE_VEHICLE = 0x4C,
};

View File

@ -431,6 +431,9 @@ VARDEF SignStruct *_new_sign_struct;
/* tunnelbridge */
#define MAX_BRIDGES 13
/* Autoreplace vehicle stuff*/
VARDEF byte _autoreplace_array[255];
/* Debugging levels */
VARDEF int _debug_spritecache_level;
VARDEF int _debug_misc_level;

178
vehicle.c
View File

@ -4,7 +4,6 @@
#include "map.h"
#include "vehicle.h"
#include "gfx.h"
//#include "station.h"
#include "viewport.h"
#include "news.h"
#include "command.h"
@ -1394,35 +1393,45 @@ extern int32 EstimateTrainCost(const RailVehicleInfo *rvi);
extern int32 EstimateRoadVehCost(byte engine_type);
extern int32 EstimateShipCost(uint16 engine_type);
extern int32 EstimateAircraftCost(uint16 engine_type);
extern int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2);
extern int32 CmdRefitShip(int x, int y, uint32 flags, uint32 p1, uint32 p2);
extern int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2);
/* Renews a vehicle
/* Replaces a vehicle (used to be called autorenew)
p1 - Index of vehicle
p2 - Type of new engine */
int32 CmdRenewVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
byte new_engine_type = p2;
/* makesvariables to inform about how much money the player wants to have left after replacing
and which engine to replace with out of p2.
the first 16 bit is the money. The last 5 digits (all 0) were removed when sent, so we add them again.
This way the max is 6553 millions and it is more than the 32 bit that is stored in _patches
This is a nice way to send 32 bit and only use 16 bit
the last 8 bit is the engine. The 8 bits in front of the engine is free so it have room for 16 bit engine entries */
uint16 new_engine_type = (uint16)(p2 & 0xFFFF);
uint32 autorefit_money = (p2 >> 16) * 100000;
Vehicle *v = DEREF_VEHICLE(p1);
int cost, build_cost;
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
if (v->type != _engines[new_engine_type].type) return CMD_ERROR;
switch (v->type) {
case VEH_Train: build_cost = EstimateTrainCost(RailVehInfo(v->engine_type)); break;
case VEH_Road: build_cost = EstimateRoadVehCost(new_engine_type); break;
case VEH_Ship: build_cost = EstimateShipCost(v->engine_type); break;
case VEH_Aircraft: build_cost = EstimateAircraftCost(new_engine_type); break;
case VEH_Train: build_cost = EstimateTrainCost(RailVehInfo(new_engine_type)); break;
case VEH_Road: build_cost = EstimateRoadVehCost(new_engine_type); break;
case VEH_Ship: build_cost = EstimateShipCost(new_engine_type); break;
case VEH_Aircraft: build_cost = EstimateAircraftCost(new_engine_type); break;
default: return CMD_ERROR;
}
/* In a rare situation, when 2 clients are connected to 1 company and have the same
settings, a vehicle can be replaced twice.. check if this is the situation here */
if (v->age == 0)
if (v->engine_type == new_engine_type && v->age == 0)
return CMD_ERROR;
/* Check if there is money for the upgrade.. if not, give a nice news-item
(that is needed, because this CMD is called automaticly) */
if (DEREF_PLAYER(v->owner)->money64 < _patches.autorenew_money + build_cost - v->value) {
if (_local_player == v->owner) {
if ( DEREF_PLAYER(v->owner)->money64 < (int32)(autorefit_money + build_cost - v->value)) {
if (( _local_player == v->owner ) && ( v->unitnumber != 0 )) { //v->unitnumber = 0 for train cars
int message;
SetDParam(0, v->unitnumber);
switch (v->type) {
@ -1439,21 +1448,106 @@ int32 CmdRenewVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return CMD_ERROR;
}
cost = build_cost - v->value;
if (flags & DC_QUERY_COST)
return cost;
if (flags & DC_EXEC) {
Engine *e;
e = &_engines[new_engine_type];
// TODO make it check if refit is possible before actually doing it
/* We do not really buy a new vehicle, we upgrade the old one */
if (v->engine_type != new_engine_type) {
/* XXX - We need to do some more stuff here, when we are going to upgrade
to a new engine! */
byte cargo_type = v->cargo_type;
v->engine_type = new_engine_type;
v->max_age = e->lifelength * 366;
/* Update limits of the vehicle (for when upgraded) */
switch (v->type) {
case VEH_Train:
// using if (true) to declare the const
{
const RailVehicleInfo *rvi = RailVehInfo(new_engine_type);
byte capacity = rvi->capacity;
v->spritenum = rvi->image_index;
v->cargo_type = rvi->cargo_type;
v->cargo_cap = rvi->capacity;
v->max_speed = rvi->max_speed;
v->u.rail.railtype = e->railtype;
// 0x0100 means that we skip the check for being stopped inside the depot
// since we do not stop it for autorefitting
if (v->cargo_type != cargo_type && capacity) {
// BUG: somehow v->index is not transfered properly
//CmdRefitRailVehicle(v->x_pos, v->y_pos, DC_EXEC, v->index , cargo_type + 0x0100 );
v->cargo_type = cargo_type; // workaround, but it do not check the refit table
} else {
v->cargo_type = rvi->cargo_type;
}
break;
}
case VEH_Road:
// using if (true) to declare the const
if (true) {
const RoadVehicleInfo *rvi = RoadVehInfo(new_engine_type);
v->spritenum = rvi->image_index;
v->cargo_type = rvi->cargo_type;
v->cargo_cap = rvi->capacity;
v->max_speed = rvi->max_speed;
break;
}
case VEH_Ship:
// using if (true) to declare the const
if (true) {
const ShipVehicleInfo *svi = ShipVehInfo(new_engine_type);
v->spritenum = svi->image_index;
v->cargo_type = svi->cargo_type;
v->cargo_cap = svi->capacity;
v->max_speed = svi->max_speed;
// 0x0100 means that we skip the check for being stopped inside the depot
// since we do not stop it for autorefitting
if (v->cargo_type != cargo_type)
CmdRefitShip(v->x_pos, v->y_pos, DC_EXEC, v->index , cargo_type + 0x0100 );
break;
}
case VEH_Aircraft:
// using if (true) to declare the const
if (true) {
const AircraftVehicleInfo *avi = AircraftVehInfo(new_engine_type);
Vehicle *u;
v->max_speed = avi->max_speed;
v->acceleration = avi->acceleration;
v->spritenum = avi->image_index;
if ( cargo_type == CT_PASSENGERS ) {
v->cargo_cap = avi->passanger_capacity;
u = v->next;
u->cargo_cap = avi->mail_capacity;
} else {
// 0x0100 means that we skip the check for being stopped inside the hangar
// since we do not stop it for autorefitting
CmdRefitAircraft(v->x_pos, v->y_pos, DC_EXEC, v->index , cargo_type + 0x0100 );
}
break;
}
default: return CMD_ERROR;
}
// makes sure that the cargo is still valid compared to new capacity
if (v->cargo_count != 0) {
if ( v->cargo_type != cargo_type )
v->cargo_count = 0;
else if ( v->cargo_count > v->cargo_cap )
v->cargo_count = v->cargo_cap;
}
}
e = &_engines[new_engine_type];
v->reliability = e->reliability;
v->reliability_spd_dec = e->reliability_spd_dec;
v->age = 0;
@ -1465,26 +1559,58 @@ int32 CmdRenewVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
}
//needs to be down here because refitting will change SET_EXPENSES_TYPE if called
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
return cost;
}
void MaybeRenewVehicle(Vehicle *v)
void MaybeReplaceVehicle(Vehicle *v)
{
uint32 new_engine_and_autoreplace_money;
if (v->owner != _local_player)
return;
// uncomment next line if you want to see what engine type just entered a depot
//printf("engine type: %d\n", v->engine_type);
// A vehicle is autorenewed when it it gets the amount of months
// give by _patches.autorenew_months away for his max age.
// Standard is -6, meaning 6 months before his max age
// It can be any value between -12 and 12.
if (!_patches.autorenew || v->age - v->max_age < (_patches.autorenew_months * 30))
return;
// Here it also checks if the vehicles is listed for replacement
if (!_patches.autorenew || v->age - v->max_age < (_patches.autorenew_months * 30)) { //replace if engine is too old
if (_autoreplace_array[v->engine_type] == v->engine_type && v->type != VEH_Train) //updates to a new model
return;
}
/* Now replace the vehicle */
_current_player = v->owner;
/* Now renew the vehicle */
DoCommandP(v->tile, v->index, v->engine_type, NULL, CMD_RENEW_VEHICLE);
/* makes the variable to inform about how much money the player wants to have left after replacing
and which engine to replace with
the first 16 bit is the money. Since we know the last 5 digits is 0, they are thrown away.
This way the max is 6553 millions and it is more than the 32 bit that is stored in _patches
This is a nice way to send 32 bit and only use 16 bit
the last 8 bit is the engine. The 8 bits in front of the engine is free so it have room for 16 bit engine entries */
new_engine_and_autoreplace_money = (((_patches.autorenew_money / 100000) & 0xFFFF) << 16)
+ _autoreplace_array[v->engine_type];
assert(v->type == _engines[ _autoreplace_array[v->engine_type] ].type);
if ( v->type != VEH_Train ) {
DoCommandP(v->tile, v->index, new_engine_and_autoreplace_money, NULL, CMD_REPLACE_VEHICLE | CMD_SHOW_NO_ERROR);
} else {
// checks if the front engine is outdated
if (v->engine_type != _autoreplace_array[v->engine_type] )
DoCommandP(v->tile, v->index, new_engine_and_autoreplace_money, NULL, CMD_REPLACE_VEHICLE | CMD_SHOW_NO_ERROR);
//we will check all the cars and engines if they should be replaced
while (v->next != NULL){
v = v->next;
if (v->engine_type != _autoreplace_array[v->engine_type] || v->age - v->max_age < (_patches.autorenew_months * 30))
DoCommandP(v->tile, v->index, new_engine_and_autoreplace_money , NULL, CMD_REPLACE_VEHICLE | CMD_SHOW_NO_ERROR);
}
}
_current_player = OWNER_NONE;
}

View File

@ -361,7 +361,7 @@ Vehicle *CheckClickOnVehicle(ViewPort *vp, int x, int y);
void DecreaseVehicleValue(Vehicle *v);
void CheckVehicleBreakdown(Vehicle *v);
void AgeVehicle(Vehicle *v);
void MaybeRenewVehicle(Vehicle *v);
void MaybeReplaceVehicle(Vehicle *v);
void DeleteCommandFromVehicleSchedule(Order cmd);

View File

@ -3,6 +3,10 @@
#include "table/strings.h"
#include "vehicle.h"
#include "window.h"
#include "engine.h"
#include "gui.h"
#include "command.h"
#include "gfx.h"
VehicleSortListingTypeFunctions * const _vehicle_sorter[] = {
&VehicleUnsortedSorter,
@ -29,6 +33,13 @@ const StringID _vehicle_sort_listing[] = {
INVALID_STRING_ID
};
const StringID _rail_types_list[] = {
STR_RAIL_VEHICLES,
STR_MONORAIL_VEHICLES,
STR_MAGLEV_VEHICLES,
INVALID_STRING_ID
};
void RebuildVehicleLists(void)
{
Window *w;
@ -294,3 +305,636 @@ int CDECL VehicleMaxSpeedSorter(const void *a, const void *b)
return (_internal_sort_order & 1) ? -r : r;
}
// this define is to match engine.c, but engine.c keeps it to itself
// ENGINE_AVAILABLE is used in ReplaceVehicleWndProc
#define ENGINE_AVAILABLE ((e->flags & 1 && HASBIT(info->railtype_climates, _opt.landscape)) || HASBIT(e->player_avail, _local_player))
/* if show_outdated is selected, it do not sort psudo engines properly but it draws all engines
* if used compined with show_cars set to false, it will work as intended. Replace window do it like that
* this was a big hack even before show_outdated was added. Stupid newgrf :p */
static void train_engine_drawing_loop(int *x, int *y, int *pos, int *sel, int *selected_id, byte railtype,
uint8 lines_drawn, bool is_engine, bool show_cars, bool show_outdated)
{
int i;
byte colour;
for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
const Engine *e = DEREF_ENGINE(i);
const RailVehicleInfo *rvi = RailVehInfo(i);
const EngineInfo *info = &_engine_info[i];
if ( rvi->power == 0 && !(show_cars) ) // disables display of cars (works since they do not have power)
continue;
if (*sel == 0) *selected_id = i;
colour = *sel == 0 ? 0xC : 0x10;
if (!(ENGINE_AVAILABLE && show_outdated && RailVehInfo(i)->power && e->railtype == railtype)) {
if (e->railtype != railtype || !(rvi->flags & RVI_WAGON) != is_engine ||
!HASBIT(e->player_avail, _local_player))
continue;
} /*else {
// TODO find a nice red colour for vehicles being replaced
if ( _autoreplace_array[i] != i )
colour = *sel == 0 ? 0x44 : 0x45;
} */
if (IS_INT_INSIDE(--*pos, -lines_drawn, 0)) {
DrawString(*x + 59, *y + 2, GetCustomEngineName(i),
colour);
DrawTrainEngine(*x + 29, *y + 6, i,
SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
*y += 14;
}
--*sel;
}
}
static void SetupScrollStuffForReplaceWindow(Window *w)
{
byte railtype;
int selected_id[2] = {-1,-1};
int sel[2] = { WP(w,replaceveh_d).sel_index[0], WP(w,replaceveh_d).sel_index[1]};
int count = 0;
int count2 = 0;
int engine_id;
switch (WP(w,replaceveh_d).vehicletype) {
case VEH_Train: {
railtype = WP(w,replaceveh_d).railtype;
for (engine_id = 0; engine_id < NUM_TRAIN_ENGINES; engine_id++) {
const Engine *e = DEREF_ENGINE(engine_id);
const EngineInfo *info = &_engine_info[engine_id];
if (ENGINE_AVAILABLE && RailVehInfo(engine_id)->power && e->railtype == railtype) {
count++;
if (sel[0]==0) selected_id[0] = engine_id;
sel[0]--;
if (HASBIT(e->player_avail, _local_player)) {
if (sel[1]==0) selected_id[1] = engine_id;
count2++;
sel[1]--;
}
}
}
break;
}
case VEH_Road: {
int num = NUM_ROAD_ENGINES;
Engine *e = &_engines[ROAD_ENGINES_INDEX];
byte cargo;
EngineInfo *info;
engine_id = ROAD_ENGINES_INDEX;
do {
info = &_engine_info[engine_id];
if (ENGINE_AVAILABLE) {
if (sel[0]==0) selected_id[0] = engine_id;
count++;
sel[0]--;
}
} while (++engine_id,++e,--num);
if ( selected_id[0] != -1 ) { // only draw right array if we have anything in the left one
num = NUM_ROAD_ENGINES;
engine_id = ROAD_ENGINES_INDEX;
e = &_engines[ROAD_ENGINES_INDEX];
cargo = RoadVehInfo(selected_id[0])->cargo_type;
do {
if ( cargo == RoadVehInfo(engine_id)->cargo_type && HASBIT(e->player_avail, _local_player)) {
count2++;
if (sel[1]==0) selected_id[1] = engine_id;
sel[1]--;
}
} while (++engine_id,++e,--num);
}
break;
}
case VEH_Ship: {
int num = NUM_SHIP_ENGINES;
Engine *e = &_engines[SHIP_ENGINES_INDEX];
byte cargo;
EngineInfo *info;
engine_id = SHIP_ENGINES_INDEX;
byte refittable;
do {
info = &_engine_info[engine_id];
if (ENGINE_AVAILABLE) {
if ( sel[0] == 0 ) selected_id[0] = engine_id;
count++;
sel[0]--;
}
} while (++engine_id,++e,--num);
if ( selected_id[0] != -1 ) {
num = NUM_SHIP_ENGINES;
e = &_engines[SHIP_ENGINES_INDEX];
engine_id = SHIP_ENGINES_INDEX;
cargo = ShipVehInfo(selected_id[0])->cargo_type;
refittable = ShipVehInfo(selected_id[0])->refittable;
do {
if (HASBIT(e->player_avail, _local_player)
&& ( cargo == ShipVehInfo(engine_id)->cargo_type || refittable & ShipVehInfo(engine_id)->refittable)) {
if ( sel[1]==0) selected_id[1] = engine_id;
sel[1]--;
count2++;
}
} while (++engine_id,++e,--num);
}
break;
} //end of ship
case VEH_Aircraft:{
int num = NUM_AIRCRAFT_ENGINES;
Engine *e = &_engines[AIRCRAFT_ENGINES_INDEX];
EngineInfo *info;
engine_id = AIRCRAFT_ENGINES_INDEX;
byte subtype;
do {
info = &_engine_info[engine_id];
if (ENGINE_AVAILABLE) {
count++;
if (sel[0]==0) selected_id[0] = engine_id;
sel[0]--;
}
} while (++engine_id,++e,--num);
if ( selected_id[0] != -1 ) {
num = NUM_AIRCRAFT_ENGINES;
e = &_engines[AIRCRAFT_ENGINES_INDEX];
subtype = AircraftVehInfo(selected_id[0])->subtype;
engine_id = AIRCRAFT_ENGINES_INDEX;
do {
if (HASBIT(e->player_avail, _local_player)) {
if ( (subtype && AircraftVehInfo(engine_id)->subtype) || (!(subtype) && !AircraftVehInfo(engine_id)->subtype) ) {
count2++;
if (sel[1]==0) selected_id[1] = engine_id;
sel[1]--;
}
}
} while (++engine_id,++e,--num);
}
break;
}
}
// sets up the number of items in each list
SetVScrollCount(w, count);
SetVScroll2Count(w, count2);
WP(w,replaceveh_d).sel_engine[0] = selected_id[0];
WP(w,replaceveh_d).sel_engine[1] = selected_id[1];
WP(w,replaceveh_d).count[0] = count;
WP(w,replaceveh_d).count[1] = count2;
return;
}
static void DrawEngineArrayInReplaceWindow(Window *w, int x, int y, int x2, int y2, int pos, int pos2,
int sel1, int sel2, int selected_id1, int selected_id2)
{
int sel[2] = {sel1, sel2};
int selected_id[2] = {selected_id1, selected_id2};
switch (WP(w,replaceveh_d).vehicletype) {
case VEH_Train: {
byte railtype = WP(w,replaceveh_d).railtype;
DrawString(157, 89 + (14 * w->vscroll.cap), _rail_types_list[railtype], 0x10);
/* draw sorting criteria string */
/* Ensure that custom engines which substituted wagons
* are sorted correctly.
* XXX - DO NOT EVER DO THIS EVER AGAIN! GRRR hacking in wagons as
* engines to get more types.. Stays here until we have our own format
* then it is exit!!! */
train_engine_drawing_loop(&x, &y, &pos, &sel[0], &selected_id[0], railtype, w->vscroll.cap, true, false, true); // True engines
train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, true, false, false); // True engines
train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, false, false, false); // Feeble wagons
break;
}
case VEH_Road: {
int num = NUM_ROAD_ENGINES;
Engine *e = &_engines[ROAD_ENGINES_INDEX];
int engine_id = ROAD_ENGINES_INDEX;
byte cargo;
EngineInfo *info;
if ( selected_id[0] >= ROAD_ENGINES_INDEX && selected_id[0] <= SHIP_ENGINES_INDEX )
cargo = RoadVehInfo(selected_id[0])->cargo_type;
do {
info = &_engine_info[engine_id];
if (ENGINE_AVAILABLE) {
if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
DrawString(x+59, y+2, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
DrawRoadVehEngine(x+29, y+6, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
y += 14;
}
if ( RoadVehInfo(engine_id)->cargo_type == cargo && HASBIT(e->player_avail, _local_player) ) {
if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0) && RoadVehInfo(engine_id)->cargo_type == cargo) {
DrawString(x2+59, y2+2, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
DrawRoadVehEngine(x2+29, y2+6, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
y2 += 14;
}
sel[1]--;
}
sel[0]--;
}
} while (++engine_id, ++e,--num);
break;
}
case VEH_Ship: {
int num = NUM_SHIP_ENGINES;
Engine *e = &_engines[SHIP_ENGINES_INDEX];
int engine_id = SHIP_ENGINES_INDEX;
byte cargo, refittable;
EngineInfo *info;
if ( selected_id[0] != -1 ) {
cargo = ShipVehInfo(selected_id[0])->cargo_type;
refittable = ShipVehInfo(selected_id[0])->refittable;
}
do {
info = &_engine_info[engine_id];
if (ENGINE_AVAILABLE) {
if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
DrawString(x+75, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
DrawShipEngine(x+35, y+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
y += 24;
}
if ( selected_id[0] != -1 ) {
if (HASBIT(e->player_avail, _local_player) && ( cargo == ShipVehInfo(engine_id)->cargo_type || refittable & ShipVehInfo(engine_id)->refittable)) {
if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) {
DrawString(x2+75, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
DrawShipEngine(x2+35, y2+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
y2 += 24;
}
sel[1]--;
}
}
sel[0]--;
}
} while (++engine_id, ++e,--num);
break;
} //end of ship
case VEH_Aircraft: {
if ( selected_id[0] != -1 ) {
int num = NUM_AIRCRAFT_ENGINES;
Engine *e = &_engines[AIRCRAFT_ENGINES_INDEX];
int engine_id = AIRCRAFT_ENGINES_INDEX;
byte subtype = AircraftVehInfo(selected_id[0])->subtype;
EngineInfo *info;
do {
info = &_engine_info[engine_id];
if (ENGINE_AVAILABLE) {
if (sel[0]==0) selected_id[0] = engine_id;
if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) {
DrawString(x+62, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10);
DrawAircraftEngine(x+29, y+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
y += 24;
}
if ( ((subtype && AircraftVehInfo(engine_id)->subtype) || (!(subtype) && !AircraftVehInfo(engine_id)->subtype))
&& HASBIT(e->player_avail, _local_player) ) {
if (sel[1]==0) selected_id[1] = engine_id;
if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) {
DrawString(x2+62, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10);
DrawAircraftEngine(x2+29, y2+10, engine_id, SPRITE_PALETTE(PLAYER_SPRITE_COLOR(_local_player)));
y2 += 24;
}
sel[1]--;
}
sel[0]--;
}
} while (++engine_id, ++e,--num);
}
break;
} // end of aircraft
}
}
static void ReplaceVehicleWndProc(Window *w, WindowEvent *e)
{
// these 3 variables is used if any of the lists is clicked
uint16 click_scroll_pos = w->vscroll2.pos;
uint16 click_scroll_cap = w->vscroll2.cap;
byte click_side = 1;
switch(e->event) {
case WE_PAINT:
{
int pos = w->vscroll.pos;
int selected_id[2] = {-1,-1};
int x = 1;
int y = 15;
int pos2 = w->vscroll2.pos;
int x2 = 1 + 228;
int y2 = 15;
int sel[2] = { WP(w,replaceveh_d).sel_index[0], WP(w,replaceveh_d).sel_index[1]};
SetupScrollStuffForReplaceWindow(w);
selected_id[0] = WP(w,replaceveh_d).sel_engine[0];
selected_id[1] = WP(w,replaceveh_d).sel_engine[1];
// sets the selected left item to the top one if it's greater than the number of vehicles in the left side
if ( WP(w,replaceveh_d).count[0] <= sel[0] ) {
if (WP(w,replaceveh_d).count[0]) {
sel[0] = 0;
WP(w,replaceveh_d).sel_index[0] = 0;
w->vscroll.pos = 0;
// now we go back to set selected_id[1] properly
SetWindowDirty(w);
return;
} else { //there are no vehicles in the left window
selected_id[1] = -1;
}
}
if ( WP(w,replaceveh_d).count[1] <= sel[1] ) {
if (WP(w,replaceveh_d).count[1]) {
sel[1] = 0;
WP(w,replaceveh_d).sel_index[1] = 0;
w->vscroll2.pos = 0;
// now we go back to set selected_id[1] properly
SetWindowDirty(w);
return;
} else { //there are no vehicles in the right window
selected_id[1] = -1;
}
}
if ( selected_id[0] == selected_id[1] || _autoreplace_array[selected_id[0]] == selected_id[1]
|| selected_id[0] == -1 || selected_id[1] == -1 )
SETBIT(w->disabled_state, 4);
else
CLRBIT(w->disabled_state, 4);
if ( _autoreplace_array[selected_id[0]] == selected_id[0] || selected_id[0] == -1 )
SETBIT(w->disabled_state, 6);
else
CLRBIT(w->disabled_state, 6);
// now the actual drawing of the window itself takes place
DrawWindowWidgets(w);
// sets up the string for the vehicle that is being replaced to
if ( selected_id[0] != -1 ) {
if ( selected_id[0] == _autoreplace_array[selected_id[0]] )
SetDParam(0, STR_NOT_REPLACING);
else
SetDParam(0, GetCustomEngineName(_autoreplace_array[selected_id[0]]));
} else {
SetDParam(0, STR_NOT_REPLACING_VEHICLE_SELECTED);
}
DrawString(145, (WP(w,replaceveh_d).line_height == 24 ? 67 : 77 ) + ( WP(w,replaceveh_d).line_height * w->vscroll.cap), STR_02BD, 0x10);
/* now we draw the two arrays according to what we just counted */
DrawEngineArrayInReplaceWindow(w, x, y, x2, y2, pos, pos2, sel[0], sel[1], selected_id[0], selected_id[1]);
WP(w,replaceveh_d).sel_engine[0] = selected_id[0];
WP(w,replaceveh_d).sel_engine[1] = selected_id[1];
/* now we draw the info about the vehicles we selected */
switch (WP(w,replaceveh_d).vehicletype) {
case VEH_Train: {
byte i = 0;
int offset = 0;
for ( i = 0 ; i < 2 ; i++) {
if ( i )
offset = 228;
if (selected_id[i] != -1) {
if (!(RailVehInfo(selected_id[i])->flags & RVI_WAGON)) {
/* it's an engine */
Set_DPARAM_Train_Engine_Build_Window(selected_id[i]);
DrawString(2 + offset, 15 + (14 * w->vscroll.cap), STR_8817_COST_WEIGHT_T_SPEED_POWER, 0);
} else {
/* it's a wagon. Train cars are not replaced with the current GUI, but this code is ready for newgrf if anybody adds that*/
Set_DPARAM_Train_Car_Build_Window(w, selected_id[i]);
DrawString(2 + offset, 15 + (14 * w->vscroll.cap), STR_8821_COST_WEIGHT_T_T_CAPACITY, 0);
}
}
}
break;
} //end if case VEH_Train
case VEH_Road: {
if (selected_id[0] != -1) {
Set_DPARAM_Road_Veh_Build_Window(selected_id[0]);
DrawString(2, 15 + (14 * w->vscroll.cap), STR_9008_COST_SPEED_RUNNING_COST, 0);
if (selected_id[1] != -1) {
Set_DPARAM_Road_Veh_Build_Window(selected_id[1]);
DrawString(2 + 228, 15 + (14 * w->vscroll.cap), STR_9008_COST_SPEED_RUNNING_COST, 0);
}
}
break;
} // end of VEH_Road
case VEH_Ship: {
if (selected_id[0] != -1) {
Set_DPARAM_Ship_Build_Window(selected_id[0]);
DrawString(2, 15 + (24 * w->vscroll.cap), STR_980A_COST_SPEED_CAPACITY_RUNNING, 0);
if (selected_id[1] != -1) {
Set_DPARAM_Ship_Build_Window(selected_id[1]);
DrawString(2 + 228, 15 + (24 * w->vscroll.cap), STR_980A_COST_SPEED_CAPACITY_RUNNING, 0);
}
}
break;
} // end of VEH_Ship
case VEH_Aircraft: {
if (selected_id[0] != -1) {
Set_DPARAM_Aircraft_Build_Window(selected_id[0]);
DrawString(2, 15 + (24 * w->vscroll.cap), STR_A007_COST_SPEED_CAPACITY_PASSENGERS, 0);
if (selected_id[1] != -1) {
Set_DPARAM_Aircraft_Build_Window(selected_id[1]);
DrawString(2 + 228, 15 + (24 * w->vscroll.cap), STR_A007_COST_SPEED_CAPACITY_PASSENGERS, 0);
}
}
break;
} // end of VEH_Aircraft
}
} // end of paint
case WE_CLICK: {
switch(e->click.widget) {
/*case 0:
DeleteWindowById(WC_REPLACE_VEHICLE, WP(w,replaceveh_d).vehicletype );
break;*/
case 14: case 15:/* Select sorting criteria dropdown menu */
// finds mask for available engines
{
int engine_avail = 0;
if ( !(HASBIT(_engines[NUM_NORMAL_RAIL_ENGINES + NUM_MONORAIL_ENGINES].player_avail, _local_player))) {
engine_avail = 4;
if ( !(HASBIT(_engines[NUM_NORMAL_RAIL_ENGINES].player_avail, _local_player)))
engine_avail = 6;
}
ShowDropDownMenu(w, _rail_types_list, WP(w,replaceveh_d).railtype, 15, engine_avail, 1);
return;
}
case 4: {
_autoreplace_array[WP(w,replaceveh_d).sel_engine[0]] = WP(w,replaceveh_d).sel_engine[1];
SetWindowDirty(w);
break;
}
case 6: {
_autoreplace_array[WP(w,replaceveh_d).sel_engine[0]] = WP(w,replaceveh_d).sel_engine[0];
SetWindowDirty(w);
break;
}
case 7:
// sets up that the left one was clicked. The default values are for the right one (9)
// this way, the code for 9 handles both sides
click_scroll_pos = w->vscroll.pos;
click_scroll_cap = w->vscroll.cap;
click_side = 0;
case 9: {
uint i = (e->click.pt.y - 14) / WP(w,replaceveh_d).line_height;
if (i < click_scroll_cap) {
WP(w,replaceveh_d).sel_index[click_side] = i + click_scroll_pos;
SetWindowDirty(w);
}
} break;
}
} break;
case WE_DROPDOWN_SELECT: { /* we have selected a dropdown item in the list */
//potiential bug: railtypes needs to be activated 0, 1, 2... If one is skipped, it messes up
WP(w,replaceveh_d).railtype = e->dropdown.index;
SetWindowDirty(w);
break;
}
}
}
static const Widget _replace_rail_vehicle_widgets[] = {
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 443, 0, 13, STR_REPLACE_VEHICLES, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, 14, 444, 455, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_PANEL, 14, 0, 227, 126, 187, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, 14, 0, 138, 200, 211, STR_REPLACE_VEHICLES_START,STR_REPLACE_HELP_START_BUTTON},
{ WWT_PANEL, 14, 139, 316, 188, 199, 0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB},
{ WWT_PUSHTXTBTN, 14, 317, 455, 200, 211, STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON},
{ WWT_MATRIX, 14, 0, 216, 14, 125, 0x801, STR_REPLACE_HELP_LEFT_ARRAY},
{ WWT_SCROLLBAR, 14, 217, 227, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_MATRIX, 14, 228, 455, 14, 125, 0x801, STR_REPLACE_HELP_RIGHT_ARRAY},
{ WWT_SCROLL2BAR, 14, 445, 455, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_PANEL, 14, 228, 455, 126, 187, 0x0, STR_NULL},
// the rest are train specific stuff
{ WWT_PANEL, 14, 0, 138, 188, 199, 0x0, STR_NULL},
{ WWT_PANEL, 3, 139, 153, 200, 211, 0x0, STR_NULL},
{ WWT_PANEL, 14, 154, 290, 200, 211, 0x0, STR_REPLACE_HELP_RAILTYPE},
{ WWT_CLOSEBOX, 14, 291, 301, 200, 210, STR_0225, STR_REPLACE_HELP_RAILTYPE},
{ WWT_PANEL, 3, 301, 316, 200, 211, 0x0, STR_NULL},
{ WWT_PANEL, 14, 317, 455, 188, 199, 0x0, STR_NULL},
{ WIDGETS_END},
};
static const Widget _replace_road_vehicle_widgets[] = {
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 443, 0, 13, STR_REPLACE_VEHICLES, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, 14, 444, 455, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_PANEL, 14, 0, 227, 126, 187, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, 14, 0, 138, 188, 199, STR_REPLACE_VEHICLES_START,STR_REPLACE_HELP_START_BUTTON},
{ WWT_PANEL, 14, 139, 316, 188, 199, 0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB},
{ WWT_PUSHTXTBTN, 14, 317, 455, 188, 199, STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON},
{ WWT_MATRIX, 14, 0, 216, 14, 125, 0x801, STR_REPLACE_HELP_LEFT_ARRAY},
{ WWT_SCROLLBAR, 14, 217, 227, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_MATRIX, 14, 228, 455, 14, 125, 0x801, STR_REPLACE_HELP_RIGHT_ARRAY},
{ WWT_SCROLL2BAR, 14, 445, 455, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_PANEL, 14, 228, 455, 126, 187, 0x0, STR_NULL},
{ WIDGETS_END},
};
static const Widget _replace_ship_aircraft_vehicle_widgets[] = {
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 443, 0, 13, STR_REPLACE_VEHICLES, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, 14, 444, 455, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_PANEL, 14, 0, 227, 110, 161, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, 14, 0, 138, 162, 173, STR_REPLACE_VEHICLES_START,STR_REPLACE_HELP_START_BUTTON},
{ WWT_PANEL, 14, 139, 316, 162, 173, 0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB},
{ WWT_PUSHTXTBTN, 14, 317, 455, 162, 173, STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON},
{ WWT_MATRIX, 14, 0, 216, 14, 109, 0x401, STR_REPLACE_HELP_LEFT_ARRAY},
{ WWT_SCROLLBAR, 14, 217, 227, 14, 109, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_MATRIX, 14, 228, 455, 14, 109, 0x401, STR_REPLACE_HELP_RIGHT_ARRAY},
{ WWT_SCROLL2BAR, 14, 445, 455, 14, 109, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_PANEL, 14, 228, 455, 110, 161, 0x0, STR_NULL},
{ WIDGETS_END},
};
static const WindowDesc _replace_rail_vehicle_desc = {
-1, -1, 456, 212,
WC_REPLACE_VEHICLE,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
_replace_rail_vehicle_widgets,
ReplaceVehicleWndProc
};
static const WindowDesc _replace_road_vehicle_desc = {
-1, -1, 456, 200,
WC_REPLACE_VEHICLE,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
_replace_road_vehicle_widgets,
ReplaceVehicleWndProc
};
static const WindowDesc _replace_ship_aircraft_vehicle_desc = {
-1, -1, 456, 174,
WC_REPLACE_VEHICLE,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
_replace_ship_aircraft_vehicle_widgets,
ReplaceVehicleWndProc
};
void ShowReplaceVehicleWindow(byte vehicletype)
{
Window *w;
DeleteWindowById(WC_REPLACE_VEHICLE, vehicletype );
switch (vehicletype) {
case VEH_Train:
w = AllocateWindowDescFront(&_replace_rail_vehicle_desc, vehicletype);
w->vscroll.cap = 8;
WP(w,replaceveh_d).line_height = 14;
break;
case VEH_Road:
w = AllocateWindowDescFront(&_replace_road_vehicle_desc, vehicletype);
w->vscroll.cap = 8;
WP(w,replaceveh_d).line_height = 14;
break;
case VEH_Ship: case VEH_Aircraft:
w = AllocateWindowDescFront(&_replace_ship_aircraft_vehicle_desc, vehicletype);
w->vscroll.cap = 4;
WP(w,replaceveh_d).line_height = 24;
break;
}
WP(w,replaceveh_d).vehicletype = vehicletype;
w->vscroll2.cap = w->vscroll.cap; // these two are always the same
}

View File

@ -42,12 +42,13 @@ typedef DEF_SORTER(VehicleSortListingTypeFunctions);
#define SORT_BY_UNSORTED 0
extern VehicleSortListingTypeFunctions * const _vehicle_sorter[];
extern const StringID _vehicle_sort_listing[];
extern const StringID _rail_types_list[];
enum VehicleSortTypes {
VEHTRAIN = 0,
VEHROAD = 1,
VEHSHIP = 2,
VEHAIRCRAFT = 3
VEHAIRCRAFT = 3
};
enum {
@ -56,4 +57,13 @@ enum {
PLY_WND_PRC__SIZE_OF_ROW_BIG = 36,
};
void ShowReplaceVehicleWindow(byte vehicletype);
void Set_DPARAM_Train_Engine_Build_Window(uint16 engine_number);
void Set_DPARAM_Train_Car_Build_Window(Window *w, uint16 engine_number);
void Set_DPARAM_Road_Veh_Build_Window(uint16 engine_number);
void Set_DPARAM_Aircraft_Build_Window(uint16 engine_number);
void Set_DPARAM_Ship_Build_Window(uint16 engine_number);
#endif /* VEHICLE_GUI_H */

248
widget.c
View File

@ -46,23 +46,37 @@ void ScrollbarClickHandler(Window *w, const Widget *wi, int x, int y)
int mi, ma, pos;
Scrollbar *sb;
if (wi->type == WWT_SCROLLBAR) {
// vertical scroller
w->flags4 &= ~WF_HSCROLL;
mi = wi->top;
ma = wi->bottom;
pos = y;
sb = &w->vscroll;
} else {
// horizontal scroller
assert(wi->type == WWT_HSCROLLBAR);
w->flags4 |= WF_HSCROLL;
mi = wi->left;
ma = wi->right;
pos = x;
sb = &w->hscroll;
switch (wi->type) {
case WWT_SCROLLBAR: {
// vertical scroller
w->flags4 &= ~WF_HSCROLL;
w->flags4 &= ~WF_SCROLL2;
mi = wi->top;
ma = wi->bottom;
pos = y;
sb = &w->vscroll;
break;
}
case WWT_SCROLL2BAR: {
// 2nd vertical scroller
w->flags4 &= ~WF_HSCROLL;
w->flags4 |= WF_SCROLL2;
mi = wi->top;
ma = wi->bottom;
pos = y;
sb = &w->vscroll2;
break;
}
case WWT_HSCROLLBAR: {
// horizontal scroller
assert(wi->type == WWT_HSCROLLBAR);
w->flags4 |= WF_HSCROLL;
mi = wi->left;
ma = wi->right;
pos = x;
sb = &w->hscroll;
}
}
if (pos <= mi+9) {
// Pressing the upper button?
if (!_demo_mode) {
@ -258,8 +272,8 @@ void DrawWindowWidgets(Window *w)
int c1,c2;
// draw up/down buttons
DrawFrameRect(r.left, r.top, r.right, r.top+9, wi->color, (w->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == WF_SCROLL_UP ? 0x20 : 0);
DrawFrameRect(r.left, r.bottom-9, r.right, r.bottom, wi->color, (w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == WF_SCROLL_DOWN ? 0x20 : 0);
DrawFrameRect(r.left, r.top, r.right, r.top+9, wi->color, (w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP ? 0x20 : 0);
DrawFrameRect(r.left, r.bottom-9, r.right, r.bottom, wi->color, (w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN ? 0x20 : 0);
// draw icons in up/down buttons
DoDrawString("\xA0", r.left+2, r.top, 0x10);
@ -279,7 +293,36 @@ void DrawWindowWidgets(Window *w)
GfxFillRect(r.left+8, r.top+10, r.left+8, r.bottom-10, c2);
pt = HandleScrollbarHittest(&w->vscroll, r.top, r.bottom);
DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == WF_SCROLL_MIDDLE ? 0x20 : 0);
DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE ? 0x20 : 0);
break;
}
case WWT_SCROLL2BAR: {
Point pt;
int c1,c2;
// draw up/down buttons
DrawFrameRect(r.left, r.top, r.right, r.top+9, wi->color, (w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2) ? 0x20 : 0);
DrawFrameRect(r.left, r.bottom-9, r.right, r.bottom, wi->color, (w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2) ? 0x20 : 0);
// draw icons in up/down buttons
DoDrawString("\xA0", r.left+2, r.top, 0x10);
DoDrawString("\xAA", r.left+2, r.bottom-9, 0x10);
c1 = _color_list[wi->color&0xF].window_color_1a;
c2 = _color_list[wi->color&0xF].window_color_2;
// draw "shaded" background
GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c2);
GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c1 | 0x8000);
// draw shaded lines
GfxFillRect(r.left+2, r.top+10, r.left+2, r.bottom-10, c1);
GfxFillRect(r.left+3, r.top+10, r.left+3, r.bottom-10, c2);
GfxFillRect(r.left+7, r.top+10, r.left+7, r.bottom-10, c1);
GfxFillRect(r.left+8, r.top+10, r.left+8, r.bottom-10, c2);
pt = HandleScrollbarHittest(&w->vscroll2, r.top, r.bottom);
DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2) ? 0x20 : 0);
break;
}
@ -383,6 +426,7 @@ draw_default:;
static uint _dropdown_item_count;
static uint32 _dropdown_disabled;
static bool _dropdown_hide_disabled;
static const StringID *_dropdown_items;
static int _dropdown_selindex;
static byte _dropdown_button;
@ -421,95 +465,100 @@ void DropdownMenuWndProc(Window *w, WindowEvent *e)
int item;
switch(e->event) {
case WE_PAINT: {
int x,y,i,sel;
uint32 dis;
case WE_PAINT: {
int x,y,i,sel;
uint32 dis;
bool hidden;
DrawWindowWidgets(w);
DrawWindowWidgets(w);
x = 1;
y = 2;
sel = _dropdown_selindex;
dis = _dropdown_disabled;
x = 1;
y = 2;
sel = _dropdown_selindex;
dis = _dropdown_disabled;
hidden = _dropdown_hide_disabled;
for(i=0; _dropdown_items[i] != INVALID_STRING_ID; i++) {
if (_dropdown_items[i] != 0) {
if (sel == 0) {
GfxFillRect(x+1, y, x+w->width-4, y + 9, 0);
for(i=0; _dropdown_items[i] != INVALID_STRING_ID; i++) {
if (!(hidden) | !(dis & 1)) {
if (_dropdown_items[i] != 0) {
if (sel == 0) {
GfxFillRect(x+1, y, x+w->width-4, y + 9, 0);
}
DrawString(x+2, y, _dropdown_items[i], sel==0 ? 12 : 16);
if (dis & 1) {
GfxFillRect(x, y, x+w->width-3, y + 9, 0x8000 +
_color_list[_dropdown_menu_widgets[0].color].window_color_bga);
}
} else {
int color_1 = _color_list[_dropdown_menu_widgets[0].color].window_color_1a;
int color_2 = _color_list[_dropdown_menu_widgets[0].color].window_color_2;
GfxFillRect(x+1, y+3, x+w->width-5, y+3, color_1);
GfxFillRect(x+1, y+4, x+w->width-5, y+4, color_2);
}
y += 10;
sel--;
}
DrawString(x+2, y, _dropdown_items[i], sel==0 ? 12 : 16);
if (dis & 1) {
GfxFillRect(x, y, x+w->width-3, y + 9, 0x8000 +
_color_list[_dropdown_menu_widgets[0].color].window_color_bga);
}
} else {
int color_1 = _color_list[_dropdown_menu_widgets[0].color].window_color_1a;
int color_2 = _color_list[_dropdown_menu_widgets[0].color].window_color_2;
GfxFillRect(x+1, y+3, x+w->width-5, y+3, color_1);
GfxFillRect(x+1, y+4, x+w->width-5, y+4, color_2);
dis>>=1;
}
y += 10;
sel--;
dis>>=1;
}
} break;
} break;
case WE_CLICK: {
item = GetDropdownItem(w);
if (item >= 0) {
_dropdown_var1 = 4;
_dropdown_selindex = item;
SetWindowDirty(w);
}
} break;
case WE_MOUSELOOP: {
Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum);
if (w2 == NULL) {
DeleteWindow(w);
return;
}
if (_dropdown_var1 != 0 && --_dropdown_var1 == 0) {
WindowEvent e;
e.event = WE_DROPDOWN_SELECT;
e.dropdown.button = _dropdown_button;
e.dropdown.index = _dropdown_selindex;
w2->wndproc(w2, &e);
DeleteWindow(w);
return;
}
if (_dropdown_var2 != 0) {
case WE_CLICK: {
item = GetDropdownItem(w);
if (item >= 0) {
_dropdown_var1 = 4;
_dropdown_selindex = item;
SetWindowDirty(w);
}
} break;
if (!_left_button_clicked) {
_dropdown_var2 = 0;
if (item < 0)
return;
_dropdown_var1 = 2;
} else {
if (item < 0)
return;
case WE_MOUSELOOP: {
Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum);
if (w2 == NULL) {
DeleteWindow(w);
return;
}
_dropdown_selindex = item;
SetWindowDirty(w);
}
} break;
if (_dropdown_var1 != 0 && --_dropdown_var1 == 0) {
WindowEvent e;
e.event = WE_DROPDOWN_SELECT;
e.dropdown.button = _dropdown_button;
e.dropdown.index = _dropdown_selindex;
w2->wndproc(w2, &e);
DeleteWindow(w);
return;
}
case WE_DESTROY: {
Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum);
if (w2 != NULL) {
CLRBIT(w2->click_state, _dropdown_button);
InvalidateWidget(w2, _dropdown_button);
}
} break;
if (_dropdown_var2 != 0) {
item = GetDropdownItem(w);
if (!_left_button_clicked) {
_dropdown_var2 = 0;
if (item < 0)
return;
_dropdown_var1 = 2;
} else {
if (item < 0)
return;
}
_dropdown_selindex = item;
SetWindowDirty(w);
}
} break;
case WE_DESTROY: {
Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum);
if (w2 != NULL) {
CLRBIT(w2->click_state, _dropdown_button);
InvalidateWidget(w2, _dropdown_button);
}
} break;
}
}
void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask)
void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, bool remove_filtered_strings)
{
WindowNumber num;
WindowClass cls;
@ -519,6 +568,7 @@ void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int butt
uint32 old_click_state = w->click_state;
_dropdown_disabled = disabled_mask;
_dropdown_hide_disabled = remove_filtered_strings;
cls = w->window_class;
num = w->window_number;
@ -549,6 +599,16 @@ void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int butt
wi = &w->widget[button];
if ( remove_filtered_strings ) {
int j;
for(j=0; _dropdown_items[j] != INVALID_STRING_ID; j++) {
if ( disabled_mask & ( 1 << j )) {
_dropdown_item_count--;
i--;
}
}
}
_dropdown_menu_widgets[0].color = wi->color;
w2 = AllocateWindow(

View File

@ -44,7 +44,7 @@ void DispatchLeftClickEvent(Window *w, int x, int y) {
case WWT_NODISTXTBTN:
break;
}
} else if (wi->type == WWT_SCROLLBAR || wi->type == WWT_HSCROLLBAR) {
} else if (wi->type == WWT_SCROLLBAR || wi->type == WWT_SCROLL2BAR || wi->type == WWT_HSCROLLBAR) {
ScrollbarClickHandler(w, wi, e.click.pt.x, e.click.pt.y);
}
@ -953,6 +953,9 @@ static bool HandleScrollbarScrolling()
if (w->flags4 & WF_HSCROLL) {
sb = &w->hscroll;
i = _cursor.pos.x - _cursorpos_drag_start.x;
} else if (w->flags4 & WF_SCROLL2){
sb = &w->vscroll2;
i = _cursor.pos.y - _cursorpos_drag_start.y;
} else {
sb = &w->vscroll;
i = _cursor.pos.y - _cursorpos_drag_start.y;

View File

@ -200,7 +200,7 @@ struct Window {
int left,top;
int width,height;
Scrollbar hscroll, vscroll;
Scrollbar hscroll, vscroll, vscroll2;
byte caption_color;
@ -254,6 +254,15 @@ typedef struct {
int16 rename_engine;
} buildtrain_d;
typedef struct {
byte railtype;
byte vehicletype;
byte sel_index[2];
int16 sel_engine[2];
uint16 count[2];
byte line_height;
} replaceveh_d;
typedef struct {
VehicleID sel;
} traindepot_d;
@ -358,7 +367,8 @@ enum WindowWidgetTypes {
WWT_HSCROLLBAR = 11,
WWT_STICKYBOX = 12,
WWT_LAST = 13, /* Last Item. use WIDGETS_END to fill up padding!! */
WWT_SCROLL2BAR = 13, /* 2nd vertical scrollbar*/
WWT_LAST = 14, /* Last Item. use WIDGETS_END to fill up padding!! */
WWT_MASK = 31,
@ -384,6 +394,7 @@ enum WindowFlags {
WF_WHITE_BORDER_ONE = 1 << 11,
WF_WHITE_BORDER_MASK = 3 << 11,
WF_SCROLL2 = 1 << 13,
};
@ -453,7 +464,7 @@ int PositionMainToolbar(Window *w);
/* widget.c */
int GetWidgetFromPos(Window *w, int x, int y);
void DrawWindowWidgets(Window *w);
void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask);
void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, bool remove_filtered_strings);
void HandleButtonClick(Window *w, byte widget);