From c0eeb710c79a29e1dbfc455abe5b1ad76479c8de Mon Sep 17 00:00:00 2001 From: truelight Date: Mon, 27 Dec 2004 18:18:44 +0000 Subject: [PATCH] (svn r1283) -Add: AutoRenew is now a client-side patch instead of a game-side patch Note: this is the first commit that breaks compatibility with 0.3.5! -Fix: Bufferoverflow with autorenew_money. It is now a 32-bit integer. --- aircraft_cmd.c | 4 +- command.c | 3 ++ command.h | 2 + roadveh_cmd.c | 4 +- settings.c | 8 ++-- settings_gui.c | 25 +++++------- ship_cmd.c | 8 ++-- train_cmd.c | 4 +- vehicle.c | 105 +++++++++++++++++++++++++++++++++++-------------- vehicle.h | 2 +- 10 files changed, 105 insertions(+), 60 deletions(-) diff --git a/aircraft_cmd.c b/aircraft_cmd.c index 7d0c5eb6ed..300e2efb36 100644 --- a/aircraft_cmd.c +++ b/aircraft_cmd.c @@ -100,7 +100,7 @@ static bool AllocateVehicles(Vehicle **vl, int num) return success; } -static int32 EstimateAircraftCost(uint16 engine_type) +int32 EstimateAircraftCost(uint16 engine_type) { return AircraftVehInfo(engine_type)->base_cost * (_price.aircraft_base>>3)>>5; } @@ -1157,7 +1157,7 @@ static void AircraftEnterHangar(Vehicle *v) ServiceAircraft(v); - MaybeRenewVehicle(v, EstimateAircraftCost(v->engine_type)); + MaybeRenewVehicle(v); TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); diff --git a/command.c b/command.c index 756c5dda25..4006848bef 100644 --- a/command.c +++ b/command.c @@ -167,6 +167,8 @@ DEF_COMMAND(CmdStartScenario); DEF_COMMAND(CmdBuildManySignals); +DEF_COMMAND(CmdRenewVehicle); + /* The master command table */ static CommandProc * const _command_proc_table[] = { CmdBuildRailroadTrack, /* 0 */ @@ -307,6 +309,7 @@ static CommandProc * const _command_proc_table[] = { CmdDestroyCompanyHQ, /* 111 */ CmdGiveMoney, /* 112 */ CmdChangePatchSetting, /* 113 */ + CmdRenewVehicle, /* 114 */ }; int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc) diff --git a/command.h b/command.h index 1918184ec2..4fadc362c6 100644 --- a/command.h +++ b/command.h @@ -148,6 +148,8 @@ enum { CMD_DESTROY_COMPANY_HQ = 111, CMD_GIVE_MONEY = 112, CMD_CHANGE_PATCH_SETTING = 113, + + CMD_RENEW_VEHICLE = 114, }; enum { diff --git a/roadveh_cmd.c b/roadveh_cmd.c index 38c6583b85..c724161601 100644 --- a/roadveh_cmd.c +++ b/roadveh_cmd.c @@ -100,7 +100,7 @@ void DrawRoadVehEngineInfo(int engine, int x, int y, int maxw) DrawStringMultiCenter(x, y, STR_902A_COST_SPEED_RUNNING_COST, maxw); } -static int32 EstimateRoadVehCost(byte engine_type) +int32 EstimateRoadVehCost(byte engine_type) { return ((_price.roadveh_base >> 3) * RoadVehInfo(engine_type)->base_cost) >> 5; } @@ -1379,7 +1379,7 @@ void RoadVehEnterDepot(Vehicle *v) InvalidateWindow(WC_VEHICLE_DETAILS, v->index); - MaybeRenewVehicle(v, EstimateRoadVehCost(v->engine_type)); + MaybeRenewVehicle(v); VehicleServiceInDepot(v); diff --git a/settings.c b/settings.c index 4c6fcaef92..e6e7b127ae 100644 --- a/settings.c +++ b/settings.c @@ -822,6 +822,10 @@ static const SettingDesc patch_player_settings[] = { {"window_snap_radius", SDT_UINT8, (void*)10, &_patches.window_snap_radius, NULL}, + {"autorenew", SDT_BOOL, (void*)false, &_patches.autorenew, NULL}, + {"autorenew_months", SDT_INT16, (void*)-6, &_patches.autorenew_months, NULL}, + {"autorenew_money", SDT_INT32, (void*)100000,&_patches.autorenew_money, NULL}, + {NULL, 0, NULL, NULL, NULL} }; @@ -870,10 +874,6 @@ const SettingDesc patch_settings[] = { {"servint_ships", SDT_UINT16, (void*)360, &_patches.servint_ships, NULL}, {"servint_aircraft", SDT_UINT16, (void*)100, &_patches.servint_aircraft, NULL}, - {"autorenew", SDT_BOOL, (void*)false, &_patches.autorenew, NULL}, - {"autorenew_months", SDT_INT16, (void*)-6, &_patches.autorenew_months, NULL}, - {"autorenew_money", SDT_INT32, (void*)100000,&_patches.autorenew_money, NULL}, - {"new_pathfinding", SDT_BOOL, (void*)true, &_patches.new_pathfinding, NULL}, {"pf_maxlength", SDT_UINT16, (void*)512, &_patches.pf_maxlength, NULL}, {"pf_maxdepth", SDT_UINT8, (void*)16, &_patches.pf_maxdepth, NULL}, diff --git a/settings_gui.c b/settings_gui.c index 1da301ce62..8e7790f34b 100644 --- a/settings_gui.c +++ b/settings_gui.c @@ -624,9 +624,9 @@ static const PatchEntry _patches_vehicles[] = { {PE_BOOL, 0, STR_CONFIG_PATCHES_NEVER_EXPIRE_VEHICLES, "never_expire_vehicles", &_patches.never_expire_vehicles,0,0,0, NULL}, {PE_UINT16, PF_0ISDIS | PF_PLAYERBASED, STR_CONFIG_PATCHES_LOST_TRAIN_DAYS, "lost_train_days", &_patches.lost_train_days, 180,720, 60, NULL}, - {PE_BOOL, 0, STR_CONFIG_PATCHES_AUTORENEW_VEHICLE,"autorenew", &_patches.autorenew, 0, 0, 0, NULL}, - {PE_INT16, 0, STR_CONFIG_PATCHES_AUTORENEW_MONTHS, "autorenew_months", &_patches.autorenew_months, -12, 12, 1, NULL}, - {PE_CURRENCY, 0, STR_CONFIG_PATCHES_AUTORENEW_MONEY,"autorenew_money", &_patches.autorenew_money, 0, 2000000, 100000, NULL}, + {PE_BOOL, PF_PLAYERBASED, STR_CONFIG_PATCHES_AUTORENEW_VEHICLE,"autorenew", &_patches.autorenew, 0, 0, 0, NULL}, + {PE_INT16, PF_PLAYERBASED, STR_CONFIG_PATCHES_AUTORENEW_MONTHS, "autorenew_months", &_patches.autorenew_months, -12, 12, 1, NULL}, + {PE_CURRENCY, PF_PLAYERBASED, STR_CONFIG_PATCHES_AUTORENEW_MONEY,"autorenew_money", &_patches.autorenew_money, 0, 2000000, 100000, NULL}, {PE_UINT8, 0, STR_CONFIG_PATCHES_MAX_TRAINS, "max_trains", &_patches.max_trains, 0,240, 10, NULL}, {PE_UINT8, 0, STR_CONFIG_PATCHES_MAX_ROADVEH, "max_roadveh", &_patches.max_roadveh, 0,240, 10, NULL}, @@ -700,7 +700,7 @@ static int32 ReadPE(const PatchEntry*pe) case PE_INT16: return *(int16*)pe->variable; case PE_UINT16: return *(uint16*)pe->variable; case PE_INT32: return *(int32*)pe->variable; - case PE_CURRENCY: return (*(int64*)pe->variable) * GetCurrentCurrencyRate(); + case PE_CURRENCY: return (*(int32*)pe->variable) * GetCurrentCurrencyRate(); default: NOT_REACHED(); } @@ -744,6 +744,7 @@ static void WritePE(const PatchEntry *pe, int32 val) *(uint16*)pe->variable = (uint16)val; break; + case PE_CURRENCY: case PE_INT32: if ((int32)val > (int32)pe->max) *(int32*)pe->variable = (int32)pe->max; else if ((int32)val < (int32)pe->min) @@ -751,14 +752,6 @@ static void WritePE(const PatchEntry *pe, int32 val) else *(int32*)pe->variable = val; break; - - case PE_CURRENCY: if ((int64)val > (int64)pe->max) - *(int64*)pe->variable = (int64)pe->max; - else if ((int64)val < (int64)pe->min) - *(int64*)pe->variable = (int64)pe->min; - else - *(int64*)pe->variable = val; - break; default: NOT_REACHED(); } @@ -1400,7 +1393,7 @@ static void CustCurrencyWndProc(Window *w, WindowEvent *e) } break; } - + if(edittext) { WP(w,def_d).data_2 = line; ShowQueryString( @@ -1412,7 +1405,7 @@ static void CustCurrencyWndProc(Window *w, WindowEvent *e) w->window_number); if (str != STR_CONFIG_PATCHES_INT32) DeleteName(str); } - + w->flags4 |= 5 << WF_TIMEOUT_SHL; SetWindowDirty(w); } break; @@ -1444,8 +1437,8 @@ static void CustCurrencyWndProc(Window *w, WindowEvent *e) break; } MarkWholeScreenDirty(); - - + + } break; case WE_TIMEOUT: diff --git a/ship_cmd.c b/ship_cmd.c index a75074d1a3..8b2879b7e7 100644 --- a/ship_cmd.c +++ b/ship_cmd.c @@ -387,7 +387,7 @@ static bool ShipAccelerate(Vehicle *v) } -static int32 EstimateShipCost(uint16 engine_type); +int32 EstimateShipCost(uint16 engine_type); static void ShipEnterDepot(Vehicle *v) { @@ -400,7 +400,7 @@ static void ShipEnterDepot(Vehicle *v) InvalidateWindow(WC_VEHICLE_DETAILS, v->index); - MaybeRenewVehicle(v, EstimateShipCost(v->engine_type)); + MaybeRenewVehicle(v); TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); @@ -680,7 +680,7 @@ static void ShipController(Vehicle *v) /* Process station in the schedule. Don't do that for buoys (HVOT_BUOY) */ st = DEREF_STATION(v->current_order.station); - if (!(st->had_vehicle_of_type & HVOT_BUOY) + if (!(st->had_vehicle_of_type & HVOT_BUOY) && (st->facilities & FACIL_DOCK)) { /* ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations */ v->current_order.type = OT_LOADING; v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD; @@ -796,7 +796,7 @@ void ShipsYearlyLoop() } } -static int32 EstimateShipCost(uint16 engine_type) +int32 EstimateShipCost(uint16 engine_type) { return ShipVehInfo(engine_type)->base_cost * (_price.ship_base>>3)>>5; } diff --git a/train_cmd.c b/train_cmd.c index 8f1b4442c8..e6ef3cb182 100644 --- a/train_cmd.c +++ b/train_cmd.c @@ -364,7 +364,7 @@ static const byte _railveh_score[] = { }; -static int32 EstimateTrainCost(const RailVehicleInfo *rvi) +int32 EstimateTrainCost(const RailVehicleInfo *rvi) { return (rvi->base_cost * (_price.build_railvehicle >> 3)) >> 5; } @@ -2618,7 +2618,7 @@ void TrainEnterDepot(Vehicle *v, uint tile) v->load_unload_time_rem = 0; v->cur_speed = 0; - MaybeRenewVehicle(v, EstimateTrainCost(RailVehInfo(v->engine_type))); + MaybeRenewVehicle(v); TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); diff --git a/vehicle.c b/vehicle.c index 2ae3aff8bf..79a3c3d8d5 100644 --- a/vehicle.c +++ b/vehicle.c @@ -25,8 +25,8 @@ void VehicleServiceInDepot(Vehicle *v) bool VehicleNeedsService(const Vehicle *v) { - return _patches.servint_ispercent ? - (v->reliability < _engines[v->engine_type].reliability * (100 - v->service_interval) / 100) : + return _patches.servint_ispercent ? + (v->reliability < _engines[v->engine_type].reliability * (100 - v->service_interval) / 100) : (v->date_of_last_service + v->service_interval < _date); } @@ -1358,6 +1358,7 @@ static void ShowVehicleGettingOld(Vehicle *v, StringID msg) { if (v->owner != _local_player) return; + // Do not show getting-old message if autorenew is active if (_patches.autorenew) return; @@ -1389,53 +1390,99 @@ void AgeVehicle(Vehicle *v) } } -void MaybeRenewVehicle(Vehicle *v, int32 build_cost) +extern int32 EstimateTrainCost(const RailVehicleInfo *rvi); +extern int32 EstimateRoadVehCost(byte engine_type); +extern int32 EstimateShipCost(uint16 engine_type); +extern int32 EstimateAircraftCost(uint16 engine_type); + +/* Renews a vehicle + p1 - Index of vehicle + p2 - Type of new engine */ +int32 CmdRenewVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2) { - Engine *e; + byte new_engine_type = p2; + Vehicle *v = DEREF_VEHICLE(p1); + int cost, build_cost; - // 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; + SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); + 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; + 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) + 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 (v->owner == _local_player) { + if (_local_player == v->owner) { int message; SetDParam(0, v->unitnumber); switch (v->type) { - case VEH_Train: message = STR_TRAIN_AUTORENEW_FAILED; break; - case VEH_Road: message = STR_ROADVEHICLE_AUTORENEW_FAILED; break; - case VEH_Ship: message = STR_SHIP_AUTORENEW_FAILED; break; - case VEH_Aircraft: message = STR_AIRCRAFT_AUTORENEW_FAILED; break; + case VEH_Train: message = STR_TRAIN_AUTORENEW_FAILED; break; + case VEH_Road: message = STR_ROADVEHICLE_AUTORENEW_FAILED; break; + case VEH_Ship: message = STR_SHIP_AUTORENEW_FAILED; break; + case VEH_Aircraft: message = STR_AIRCRAFT_AUTORENEW_FAILED; break; // This should never happen default: message = 0; break; } AddNewsItem(message, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0); } - return; + + return CMD_ERROR; } - // Withdraw the money from the right player ;) - _current_player = v->owner; + cost = build_cost - v->value; - e = &_engines[v->engine_type]; - v->reliability = e->reliability; - v->reliability_spd_dec = e->reliability_spd_dec; - v->age = 0; + if (flags & DC_QUERY_COST) + return cost; - v->date_of_last_service = _date; - v->build_year = _cur_year; + if (flags & DC_EXEC) { + Engine *e; - SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); - SubtractMoneyFromPlayer(build_cost - v->value); - v->value = build_cost; + /* 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! */ + } + e = &_engines[new_engine_type]; + v->reliability = e->reliability; + v->reliability_spd_dec = e->reliability_spd_dec; + v->age = 0; - InvalidateWindow(WC_VEHICLE_DETAILS, v->index); + v->date_of_last_service = _date; + v->build_year = _cur_year; + + v->value = build_cost; + + InvalidateWindow(WC_VEHICLE_DETAILS, v->index); + } + + return cost; +} + +void MaybeRenewVehicle(Vehicle *v) +{ + if (v->owner != _local_player) + return; + + // 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; - _current_player = OWNER_NONE; + /* Now renew the vehicle */ + DoCommandP(v->tile, v->index, v->engine_type, NULL, CMD_RENEW_VEHICLE); } diff --git a/vehicle.h b/vehicle.h index 5512447053..de9aac5b2d 100644 --- a/vehicle.h +++ b/vehicle.h @@ -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, int32 build_cost); +void MaybeRenewVehicle(Vehicle *v); void DeleteCommandFromVehicleSchedule(Order cmd);