111 } |
111 } |
112 |
112 |
113 v->next_order = OT_GOTO_DEPOT | OF_NON_STOP; |
113 v->next_order = OT_GOTO_DEPOT | OF_NON_STOP; |
114 v->next_order_param = (byte)i; |
114 v->next_order_param = (byte)i; |
115 v->dest_tile = (&_depots[i])->xy; |
115 v->dest_tile = (&_depots[i])->xy; |
116 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
116 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
117 } |
117 } |
118 |
118 |
119 void OnNewDay_Ship(Vehicle *v) |
119 void OnNewDay_Ship(Vehicle *v) |
120 { |
120 { |
121 int32 cost; |
121 int32 cost; |
126 CheckVehicleBreakdown(v); |
126 CheckVehicleBreakdown(v); |
127 AgeVehicle(v); |
127 AgeVehicle(v); |
128 CheckIfShipNeedsService(v); |
128 CheckIfShipNeedsService(v); |
129 |
129 |
130 CheckOrders(v); |
130 CheckOrders(v); |
131 |
131 |
132 if (v->vehstatus & VS_STOPPED) |
132 if (v->vehstatus & VS_STOPPED) |
133 return; |
133 return; |
134 |
134 |
135 |
135 |
136 |
136 |
137 cost = ship_vehicle_info(v->engine_type).running_cost * _price.ship_running / 364; |
137 cost = ship_vehicle_info(v->engine_type).running_cost * _price.ship_running / 364; |
138 v->profit_this_year -= cost >> 8; |
138 v->profit_this_year -= cost >> 8; |
139 |
139 |
140 SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN); |
140 SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN); |
150 v->breakdown_ctr = 1; |
150 v->breakdown_ctr = 1; |
151 v->cur_speed = 0; |
151 v->cur_speed = 0; |
152 |
152 |
153 if (v->breakdowns_since_last_service != 255) |
153 if (v->breakdowns_since_last_service != 255) |
154 v->breakdowns_since_last_service++; |
154 v->breakdowns_since_last_service++; |
155 |
155 |
156 InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
156 InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
157 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
157 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
158 |
158 |
159 SndPlayVehicleFx((_opt.landscape != LT_CANDY) ? 0xE : 0x3A, v); |
159 SndPlayVehicleFx((_opt.landscape != LT_CANDY) ? 0xE : 0x3A, v); |
160 |
160 |
161 if (!(v->vehstatus & VS_HIDDEN)) { |
161 if (!(v->vehstatus & VS_HIDDEN)) { |
162 Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE); |
162 Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE); |
163 if (u) |
163 if (u) |
229 v->next_order_param = (byte)(order >> 8); |
229 v->next_order_param = (byte)(order >> 8); |
230 |
230 |
231 if ((order & OT_MASK) == OT_GOTO_STATION) { |
231 if ((order & OT_MASK) == OT_GOTO_STATION) { |
232 if ( (byte)(order >> 8) == v->last_station_visited) |
232 if ( (byte)(order >> 8) == v->last_station_visited) |
233 v->last_station_visited = 0xFF; |
233 v->last_station_visited = 0xFF; |
234 |
234 |
235 st = DEREF_STATION(order >> 8); |
235 st = DEREF_STATION(order >> 8); |
236 if (st->dock_tile != 0) { |
236 if (st->dock_tile != 0) { |
237 v->dest_tile = TILE_ADD(st->dock_tile, _dock_offs[_map5[st->dock_tile]-0x4B]); |
237 v->dest_tile = TILE_ADD(st->dock_tile, _dock_offs[_map5[st->dock_tile]-0x4B]); |
238 } |
238 } |
239 } else if ((order & OT_MASK) == OT_GOTO_DEPOT) { |
239 } else if ((order & OT_MASK) == OT_GOTO_DEPOT) { |
246 |
246 |
247 static void HandleShipLoading(Vehicle *v) |
247 static void HandleShipLoading(Vehicle *v) |
248 { |
248 { |
249 if (v->next_order == OT_NOTHING) |
249 if (v->next_order == OT_NOTHING) |
250 return; |
250 return; |
251 |
251 |
252 if (v->next_order != OT_DUMMY) { |
252 if (v->next_order != OT_DUMMY) { |
253 if ((v->next_order&OT_MASK) != OT_LOADING) |
253 if ((v->next_order&OT_MASK) != OT_LOADING) |
254 return; |
254 return; |
255 |
255 |
256 if (--v->load_unload_time_rem) |
256 if (--v->load_unload_time_rem) |
350 |
350 |
351 spd = min(v->cur_speed + 1, v->max_speed); |
351 spd = min(v->cur_speed + 1, v->max_speed); |
352 |
352 |
353 //updates statusbar only if speed have changed to save CPU time |
353 //updates statusbar only if speed have changed to save CPU time |
354 if (spd != v->cur_speed) { |
354 if (spd != v->cur_speed) { |
355 v->cur_speed = spd; |
355 v->cur_speed = spd; |
356 if (_patches.vehicle_speed) |
356 if (_patches.vehicle_speed) |
357 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
357 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
358 } |
358 } |
359 |
359 |
360 // Decrease somewhat when turning |
360 // Decrease somewhat when turning |
382 |
382 |
383 v->u.ship.state = 0x80; |
383 v->u.ship.state = 0x80; |
384 v->vehstatus |= VS_HIDDEN; |
384 v->vehstatus |= VS_HIDDEN; |
385 v->cur_speed = 0; |
385 v->cur_speed = 0; |
386 RecalcShipStuff(v); |
386 RecalcShipStuff(v); |
387 |
387 |
388 v->date_of_last_service = _date; |
388 v->date_of_last_service = _date; |
389 v->breakdowns_since_last_service = 0; |
389 v->breakdowns_since_last_service = 0; |
390 v->reliability = _engines[v->engine_type].reliability; |
390 v->reliability = _engines[v->engine_type].reliability; |
391 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
391 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
392 |
392 |
393 MaybeRenewVehicle(v, EstimateShipCost(v->engine_type)); |
393 MaybeRenewVehicle(v, EstimateShipCost(v->engine_type)); |
394 |
394 |
395 if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT) { |
395 if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT) { |
396 InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
396 InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
397 |
397 |
398 t = v->next_order; |
398 t = v->next_order; |
399 v->next_order = OT_DUMMY; |
399 v->next_order = OT_DUMMY; |
400 |
400 |
401 if (t&OF_UNLOAD) { v->cur_order_index++; } |
401 if (t&OF_UNLOAD) { v->cur_order_index++; } |
402 |
402 |
442 static bool ShipTrackFollower(uint tile, PathFindShip *pfs, int track, uint length, byte *state) |
442 static bool ShipTrackFollower(uint tile, PathFindShip *pfs, int track, uint length, byte *state) |
443 { |
443 { |
444 // Found dest? |
444 // Found dest? |
445 if (tile == pfs->dest_coords) { |
445 if (tile == pfs->dest_coords) { |
446 pfs->best_bird_dist = 0; |
446 pfs->best_bird_dist = 0; |
447 |
447 |
448 // if (length < pfs->best_length) |
448 // if (length < pfs->best_length) |
449 // dbg_store_path(); |
449 // dbg_store_path(); |
450 |
450 |
451 pfs->best_length = minu(pfs->best_length, length); |
451 pfs->best_length = minu(pfs->best_length, length); |
452 return true; |
452 return true; |
454 |
454 |
455 // Skip this tile in the calculation |
455 // Skip this tile in the calculation |
456 if (tile != pfs->skiptile) { |
456 if (tile != pfs->skiptile) { |
457 pfs->best_bird_dist = minu(pfs->best_bird_dist, GetTileDist1Db(pfs->dest_coords, tile)); |
457 pfs->best_bird_dist = minu(pfs->best_bird_dist, GetTileDist1Db(pfs->dest_coords, tile)); |
458 } |
458 } |
459 |
459 |
460 return false; |
460 return false; |
461 } |
461 } |
462 |
462 |
463 static const byte _ship_search_directions[6][4] = { |
463 static const byte _ship_search_directions[6][4] = { |
464 { 0, 9, 2, 9 }, |
464 { 0, 9, 2, 9 }, |
486 best_track = -1; |
486 best_track = -1; |
487 |
487 |
488 do { |
488 do { |
489 i = FIND_FIRST_BIT(bits); |
489 i = FIND_FIRST_BIT(bits); |
490 bits = KILL_FIRST_BIT(bits); |
490 bits = KILL_FIRST_BIT(bits); |
491 |
491 |
492 pfs.best_bird_dist = (uint)-1; |
492 pfs.best_bird_dist = (uint)-1; |
493 pfs.best_length = (uint)-1; |
493 pfs.best_length = (uint)-1; |
494 |
494 |
495 FollowTrack(tile, 0x3800 | TRANSPORT_WATER, _ship_search_directions[i][dir], (TPFEnumProc*)ShipTrackFollower, NULL, &pfs); |
495 FollowTrack(tile, 0x3800 | TRANSPORT_WATER, _ship_search_directions[i][dir], (TPFEnumProc*)ShipTrackFollower, NULL, &pfs); |
496 |
496 |
497 if (best_track >= 0) { |
497 if (best_track >= 0) { |
498 if (pfs.best_bird_dist != 0) { |
498 if (pfs.best_bird_dist != 0) { |
499 /* neither reached the destination, pick the one with the smallest bird dist */ |
499 /* neither reached the destination, pick the one with the smallest bird dist */ |
500 if (pfs.best_bird_dist > best_bird_dist) goto bad; |
500 if (pfs.best_bird_dist > best_bird_dist) goto bad; |
501 if (pfs.best_bird_dist < best_bird_dist) goto good; |
501 if (pfs.best_bird_dist < best_bird_dist) goto good; |
502 } else { |
502 } else { |
503 if (pfs.best_length > best_length) goto bad; |
503 if (pfs.best_length > best_length) goto bad; |
504 if (pfs.best_length < best_length) goto good; |
504 if (pfs.best_length < best_length) goto good; |
505 } |
505 } |
506 |
506 |
507 /* if we reach this position, there's two paths of equal value so far. |
507 /* if we reach this position, there's two paths of equal value so far. |
508 * pick one randomly. */ |
508 * pick one randomly. */ |
509 r = (byte)Random(); |
509 r = (byte)Random(); |
510 if (_pick_shiptrack_table[i] == ship_dir) r += 80; |
510 if (_pick_shiptrack_table[i] == ship_dir) r += 80; |
511 if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80; |
511 if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80; |
512 if (r <= 127) goto bad; |
512 if (r <= 127) goto bad; |
552 2, 3, 4, |
552 2, 3, 4, |
553 }; |
553 }; |
554 |
554 |
555 static int ShipGetNewDirectionFromTiles(uint new_tile, uint old_tile) |
555 static int ShipGetNewDirectionFromTiles(uint new_tile, uint old_tile) |
556 { |
556 { |
557 uint offs = (GET_TILE_Y(new_tile) - GET_TILE_Y(old_tile) + 1) * 4 + |
557 uint offs = (GET_TILE_Y(new_tile) - GET_TILE_Y(old_tile) + 1) * 4 + |
558 GET_TILE_X(new_tile) - GET_TILE_X(old_tile) + 1; |
558 GET_TILE_X(new_tile) - GET_TILE_X(old_tile) + 1; |
559 assert(offs < 11 && offs != 3 && offs != 7); |
559 assert(offs < 11 && offs != 3 && offs != 7); |
560 return _new_vehicle_direction_table[offs]; |
560 return _new_vehicle_direction_table[offs]; |
561 } |
561 } |
562 |
562 |
705 track = ChooseShipTrack(v, gp.new_tile, dir, tracks); |
705 track = ChooseShipTrack(v, gp.new_tile, dir, tracks); |
706 if (track < 0) |
706 if (track < 0) |
707 goto reverse_direction; |
707 goto reverse_direction; |
708 |
708 |
709 b = _ship_subcoord[dir][track]; |
709 b = _ship_subcoord[dir][track]; |
710 |
710 |
711 gp.x = (gp.x&~0xF) | b[0]; |
711 gp.x = (gp.x&~0xF) | b[0]; |
712 gp.y = (gp.y&~0xF) | b[1]; |
712 gp.y = (gp.y&~0xF) | b[1]; |
713 |
713 |
714 /* Call the landscape function and tell it that the vehicle entered the tile */ |
714 /* Call the landscape function and tell it that the vehicle entered the tile */ |
715 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
715 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
792 int32 value; |
792 int32 value; |
793 Vehicle *v; |
793 Vehicle *v; |
794 uint unit_num; |
794 uint unit_num; |
795 uint tile = TILE_FROM_XY(x,y); |
795 uint tile = TILE_FROM_XY(x,y); |
796 Engine *e; |
796 Engine *e; |
797 |
797 |
798 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
798 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
799 |
799 |
800 value = EstimateShipCost(p1); |
800 value = EstimateShipCost(p1); |
801 if (flags & DC_QUERY_COST) |
801 if (flags & DC_QUERY_COST) |
802 return value; |
802 return value; |
803 |
803 |
804 v = AllocateVehicle(); |
804 v = AllocateVehicle(); |
805 if (v == NULL || _ptr_to_next_order >= endof(_order_array) || |
805 if (v == NULL || _ptr_to_next_order >= endof(_order_array) || |
806 (unit_num = GetFreeUnitNumber(VEH_Ship)) > _patches.max_ships) |
806 (unit_num = GetFreeUnitNumber(VEH_Ship)) > _patches.max_ships) |
807 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
807 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
808 |
808 |
809 if (flags & DC_EXEC) { |
809 if (flags & DC_EXEC) { |
810 v->unitnumber = unit_num; |
810 v->unitnumber = unit_num; |
811 |
811 |
812 v->owner = _current_player; |
812 v->owner = _current_player; |
813 v->tile = tile; |
813 v->tile = tile; |
821 v->sprite_width = 6; |
821 v->sprite_width = 6; |
822 v->sprite_height = 6; |
822 v->sprite_height = 6; |
823 v->x_offs = -3; |
823 v->x_offs = -3; |
824 v->y_offs = -3; |
824 v->y_offs = -3; |
825 v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; |
825 v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; |
826 |
826 |
827 v->spritenum = ship_vehicle_info(p1).image_index; |
827 v->spritenum = ship_vehicle_info(p1).image_index; |
828 v->cargo_type = ship_vehicle_info(p1).cargo_type; |
828 v->cargo_type = ship_vehicle_info(p1).cargo_type; |
829 v->cargo_cap = ship_vehicle_info(p1).capacity; |
829 v->cargo_cap = ship_vehicle_info(p1).capacity; |
830 v->value = value; |
830 v->value = value; |
831 |
831 |
832 v->last_station_visited = 255; |
832 v->last_station_visited = 255; |
833 v->max_speed = ship_vehicle_info(p1).max_speed; |
833 v->max_speed = ship_vehicle_info(p1).max_speed; |
834 v->engine_type = (byte)p1; |
834 v->engine_type = (byte)p1; |
835 |
835 |
836 e = &_engines[p1]; |
836 e = &_engines[p1]; |
854 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
854 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
855 _vehicle_sort_dirty[VEHSHIP] = true; // build a ship |
855 _vehicle_sort_dirty[VEHSHIP] = true; // build a ship |
856 InvalidateWindow(WC_SHIPS_LIST, v->owner); |
856 InvalidateWindow(WC_SHIPS_LIST, v->owner); |
857 InvalidateWindow(WC_COMPANY, v->owner); |
857 InvalidateWindow(WC_COMPANY, v->owner); |
858 } |
858 } |
859 |
859 |
860 return value; |
860 return value; |
861 } |
861 } |
862 |
862 |
863 int32 CmdSellShip(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
863 int32 CmdSellShip(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
864 { |
864 { |
865 Vehicle *v; |
865 Vehicle *v; |
866 |
866 |
867 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
867 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
868 |
868 |
869 v = &_vehicles[p1]; |
869 v = &_vehicles[p1]; |
870 |
870 |
871 if (!CheckOwnership(v->owner)) |
871 if (!CheckOwnership(v->owner)) |
872 return CMD_ERROR; |
872 return CMD_ERROR; |
873 |
873 |
874 if (!IsShipDepotTile(v->tile) || v->u.road.state != 0x80 || !(v->vehstatus&VS_STOPPED)) |
874 if (!IsShipDepotTile(v->tile) || v->u.road.state != 0x80 || !(v->vehstatus&VS_STOPPED)) |
875 return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN); |
875 return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN); |
876 |
876 |
877 if (flags & DC_EXEC) { |
877 if (flags & DC_EXEC) { |
878 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
878 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
879 _vehicle_sort_dirty[VEHSHIP] = true; // sell a ship |
879 _vehicle_sort_dirty[VEHSHIP] = true; // sell a ship |
880 InvalidateWindow(WC_SHIPS_LIST, v->owner); |
880 InvalidateWindow(WC_SHIPS_LIST, v->owner); |
881 InvalidateWindow(WC_COMPANY, v->owner); |
881 InvalidateWindow(WC_COMPANY, v->owner); |
882 DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
882 DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
883 DeleteVehicle(v); |
883 DeleteVehicle(v); |
884 } |
884 } |
885 |
885 |
886 return -(int32)v->value; |
886 return -(int32)v->value; |
887 } |
887 } |
888 |
888 |
889 // p1 = vehicle |
889 // p1 = vehicle |
890 int32 CmdStartStopShip(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
890 int32 CmdStartStopShip(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
917 |
917 |
918 if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT) { |
918 if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT) { |
919 if (flags & DC_EXEC) { |
919 if (flags & DC_EXEC) { |
920 if (v->next_order&OF_UNLOAD) {v->cur_order_index++;} |
920 if (v->next_order&OF_UNLOAD) {v->cur_order_index++;} |
921 v->next_order = OT_DUMMY; |
921 v->next_order = OT_DUMMY; |
922 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
922 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4); |
923 } |
923 } |
924 } else { |
924 } else { |
925 depot = FindClosestShipDepot(v); |
925 depot = FindClosestShipDepot(v); |
926 if (depot < 0) |
926 if (depot < 0) |
927 return_cmd_error(STR_981A_UNABLE_TO_FIND_LOCAL_DEPOT); |
927 return_cmd_error(STR_981A_UNABLE_TO_FIND_LOCAL_DEPOT); |