truelight@0: #include "stdafx.h" truelight@0: #include "ttd.h" tron@507: #include "table/strings.h" truelight@0: #include "vehicle.h" truelight@0: #include "command.h" truelight@0: #include "station.h" truelight@0: #include "player.h" dominik@19: #include "news.h" truelight@0: truelight@0: /* p1 & 0xFFFF = vehicle truelight@0: * p1 >> 16 = index in order list truelight@0: * p2 = order command to insert truelight@0: */ truelight@0: int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) truelight@0: { truelight@0: Vehicle *v = &_vehicles[p1 & 0xFFFF]; truelight@0: int sel = p1 >> 16; truelight@0: int t; truelight@0: truelight@0: if (sel > v->num_orders) return_cmd_error(STR_EMPTY); truelight@0: if (_ptr_to_next_order == endof(_order_array)) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS); truelight@0: if (v->num_orders >= 40) return_cmd_error(STR_8832_TOO_MANY_ORDERS); truelight@0: truelight@0: // for ships, make sure that the station is not too far away from the previous destination. truelight@0: if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) && truelight@0: sel != 0 && ((t=v->schedule_ptr[sel-1])&OT_MASK) == OT_GOTO_STATION) { truelight@193: truelight@0: int dist = GetTileDist(DEREF_STATION(t >> 8)->xy, DEREF_STATION(p2 >> 8)->xy); truelight@0: if (dist >= 130) truelight@0: return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO); truelight@0: } truelight@0: truelight@0: if (flags & DC_EXEC) { truelight@0: uint16 *s1, *s2; truelight@0: Vehicle *u; truelight@0: truelight@0: s1 = &v->schedule_ptr[sel]; truelight@0: s2 = _ptr_to_next_order++; truelight@0: do s2[1] = s2[0]; while (--s2 >= s1); truelight@0: s1[0] = (uint16)p2; truelight@0: truelight@0: s1 = v->schedule_ptr; truelight@193: truelight@0: FOR_ALL_VEHICLES(u) { truelight@0: if (u->type != 0 && u->schedule_ptr != NULL) { truelight@0: if (s1 < u->schedule_ptr) { truelight@0: u->schedule_ptr++; truelight@0: } else if (s1 == u->schedule_ptr) { // handle shared orders truelight@0: u->num_orders++; truelight@0: truelight@0: if ((byte)sel <= u->cur_order_index) { truelight@0: sel++; truelight@0: if ((byte)sel < u->num_orders) truelight@0: u->cur_order_index = sel; truelight@0: } truelight@0: InvalidateWindow(WC_VEHICLE_VIEW, u->index); truelight@0: InvalidateWindow(WC_VEHICLE_ORDERS, u->index); truelight@0: } truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: return 0; truelight@0: } truelight@0: truelight@0: static int32 DecloneOrder(Vehicle *dst, uint32 flags) truelight@0: { truelight@0: if (_ptr_to_next_order == endof(_order_array)) truelight@0: return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS); truelight@0: truelight@0: if (flags & DC_EXEC) { truelight@0: DeleteVehicleSchedule(dst); truelight@193: truelight@0: dst->num_orders = 0; truelight@0: *(dst->schedule_ptr = _ptr_to_next_order++) = 0; truelight@193: truelight@0: InvalidateWindow(WC_VEHICLE_ORDERS, dst->index); truelight@0: } truelight@0: return 0; truelight@0: } truelight@0: truelight@0: /* p1 = vehicle truelight@0: * p2 = sel truelight@0: */ truelight@0: int32 CmdDeleteOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) truelight@0: { truelight@0: Vehicle *v = &_vehicles[p1], *u; truelight@0: uint sel = (uint)p2; truelight@0: truelight@0: _error_message = STR_EMPTY; truelight@0: if (sel >= v->num_orders) truelight@0: return DecloneOrder(v, flags); truelight@0: truelight@0: if (flags & DC_EXEC) { truelight@0: uint16 *s1; truelight@193: truelight@0: s1 = &v->schedule_ptr[sel]; truelight@0: truelight@0: // copy all orders to get rid of the hole truelight@0: do s1[0] = s1[1]; while (++s1 != _ptr_to_next_order); truelight@0: _ptr_to_next_order--; truelight@0: truelight@0: s1 = v->schedule_ptr; truelight@0: truelight@0: FOR_ALL_VEHICLES(u) { truelight@0: if (u->type != 0 && u->schedule_ptr != NULL) { truelight@0: if (s1 < u->schedule_ptr) { truelight@0: u->schedule_ptr--; truelight@0: } else if (s1 == u->schedule_ptr) {// handle shared orders truelight@0: u->num_orders--; truelight@0: if ((byte)sel < u->cur_order_index) truelight@0: u->cur_order_index--; truelight@0: truelight@0: if ((byte)sel == u->cur_order_index && (u->next_order&(OT_MASK|OF_NON_STOP)) == (OT_LOADING|OF_NON_STOP)) truelight@0: u->next_order = OT_LOADING; truelight@0: truelight@0: InvalidateWindow(WC_VEHICLE_VIEW, u->index); truelight@0: InvalidateWindow(WC_VEHICLE_ORDERS, u->index); truelight@0: } truelight@0: } truelight@0: } truelight@0: } truelight@193: truelight@0: return 0; truelight@0: } truelight@0: truelight@0: /* p1 = vehicle */ truelight@0: int32 CmdSkipOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) truelight@0: { truelight@0: if (flags & DC_EXEC) { truelight@0: Vehicle *v = &_vehicles[p1]; truelight@0: truelight@0: { truelight@0: byte b = v->cur_order_index + 1; truelight@0: if (b >= v->num_orders) b = 0; truelight@0: v->cur_order_index = b; truelight@193: truelight@0: if (v->type == VEH_Train) truelight@0: v->u.rail.days_since_order_progr = 0; truelight@0: } truelight@0: truelight@0: if ((v->next_order&(OT_MASK|OF_NON_STOP)) == (OT_LOADING|OF_NON_STOP)) truelight@0: v->next_order = OT_LOADING; truelight@0: truelight@0: InvalidateWindow(WC_VEHICLE_ORDERS, v->index); truelight@0: } truelight@0: return 0; truelight@0: } truelight@0: truelight@0: /* p1 = vehicle truelight@0: * p2&0xFF = sel truelight@0: * p2>>8 = mode truelight@0: */ truelight@0: int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) truelight@0: { truelight@0: Vehicle *v = &_vehicles[p1]; truelight@0: byte sel = (byte)p2; truelight@0: uint16 *sched; truelight@0: truelight@0: if (sel >= v->num_orders) truelight@0: return CMD_ERROR; truelight@0: truelight@0: sched = &v->schedule_ptr[sel]; truelight@193: if (!((*sched & OT_MASK) == OT_GOTO_STATION || truelight@0: ((*sched & OT_MASK) == OT_GOTO_DEPOT && (p2>>8) != 1))) truelight@0: return CMD_ERROR; truelight@0: truelight@0: if (flags & DC_EXEC) { truelight@0: switch(p2 >> 8) { truelight@0: case 0: // full load truelight@0: *sched ^= OF_FULL_LOAD; truelight@0: if ((*sched & OT_MASK) != OT_GOTO_DEPOT) truelight@0: *sched &= ~OF_UNLOAD; truelight@0: break; truelight@0: case 1: // unload truelight@0: *sched ^= OF_UNLOAD; truelight@0: *sched &= ~OF_FULL_LOAD; truelight@0: break; truelight@0: case 2: // non stop truelight@0: *sched ^= OF_NON_STOP; truelight@0: break; truelight@0: } truelight@0: sched = v->schedule_ptr; truelight@0: truelight@0: FOR_ALL_VEHICLES(v) { truelight@0: if (v->schedule_ptr == sched) truelight@0: InvalidateWindow(WC_VEHICLE_ORDERS, v->index); truelight@0: } truelight@193: truelight@0: } truelight@193: truelight@0: return 0; truelight@0: } truelight@0: truelight@0: // Clone an order truelight@0: // p1 & 0xFFFF is destination vehicle truelight@0: // p1 >> 16 is source vehicle truelight@0: truelight@0: // p2 is truelight@0: // 0 - clone truelight@0: // 1 - copy truelight@0: // 2 - unclone truelight@0: truelight@0: truelight@0: int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) truelight@0: { truelight@0: Vehicle *dst = &_vehicles[p1 & 0xFFFF]; truelight@193: truelight@0: if (!(dst->type && dst->owner == _current_player)) truelight@0: return CMD_ERROR; truelight@0: truelight@0: switch(p2) { truelight@193: truelight@0: // share vehicle orders? truelight@0: case 0: { truelight@0: Vehicle *src = &_vehicles[p1 >> 16]; truelight@0: truelight@0: // sanity checks truelight@0: if (!(src->owner == _current_player && dst->type == src->type && dst != src)) truelight@0: return CMD_ERROR; truelight@193: darkvater@29: // let's see what happens with road vehicles darkvater@29: if (src->type == VEH_Road) { darkvater@29: if (src->cargo_type != dst->cargo_type && (src->cargo_type == CT_PASSENGERS || dst->cargo_type == CT_PASSENGERS)) darkvater@29: return CMD_ERROR; darkvater@29: } truelight@0: truelight@0: if (flags & DC_EXEC) { truelight@0: DeleteVehicleSchedule(dst); truelight@0: dst->schedule_ptr = src->schedule_ptr; truelight@0: dst->num_orders = src->num_orders; truelight@0: truelight@0: InvalidateWindow(WC_VEHICLE_ORDERS, src->index); truelight@0: InvalidateWindow(WC_VEHICLE_ORDERS, dst->index); truelight@0: } truelight@0: break; truelight@0: } truelight@0: truelight@0: // copy vehicle orders? truelight@0: case 1: { truelight@0: Vehicle *src = &_vehicles[p1 >> 16]; truelight@0: int delta; truelight@0: truelight@0: // sanity checks truelight@0: if (!(src->owner == _current_player && dst->type == src->type && dst != src)) truelight@0: return CMD_ERROR; truelight@193: darkvater@29: // let's see what happens with road vehicles darkvater@29: if (src->type == VEH_Road) { darkvater@29: uint16 ord; darkvater@29: int i; darkvater@29: Station *st; darkvater@29: TileIndex required_dst; truelight@193: darkvater@29: for (i=0; (ord = src->schedule_ptr[i]) != 0; i++) { darkvater@29: if ( ( ord & OT_MASK ) == OT_GOTO_STATION ) { darkvater@29: st = DEREF_STATION(ord >> 8); darkvater@29: required_dst = (dst->cargo_type == CT_PASSENGERS) ? st->bus_tile : st->lorry_tile; darkvater@29: if ( !required_dst ) darkvater@29: return CMD_ERROR; darkvater@29: } darkvater@29: } darkvater@29: } truelight@0: truelight@0: // make sure there's orders available truelight@0: delta = IsScheduleShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders; truelight@0: if (delta > endof(_order_array) - _ptr_to_next_order) truelight@0: return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS); truelight@0: truelight@0: if (flags & DC_EXEC) { truelight@0: DeleteVehicleSchedule(dst); truelight@0: dst->schedule_ptr = _ptr_to_next_order; truelight@0: dst->num_orders = src->num_orders; truelight@0: _ptr_to_next_order += src->num_orders + 1; truelight@0: memcpy(dst->schedule_ptr, src->schedule_ptr, (src->num_orders + 1) * sizeof(uint16)); truelight@0: truelight@0: InvalidateWindow(WC_VEHICLE_ORDERS, dst->index); truelight@0: } truelight@0: break; truelight@0: } truelight@0: truelight@0: // declone vehicle orders? truelight@0: case 2: return DecloneOrder(dst, flags); truelight@0: } truelight@0: truelight@0: return 0; truelight@0: } truelight@0: truelight@0: void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak) truelight@0: { truelight@0: Vehicle *u = IsScheduleShared(v); truelight@0: uint16 *sched, ord, *os; truelight@0: truelight@0: bak->orderindex = v->cur_order_index; truelight@0: bak->service_interval = v->service_interval; truelight@193: truelight@0: if ((v->string_id & 0xF800) != 0x7800) { truelight@0: bak->name[0] = 0; truelight@0: } else { truelight@0: GetName(v->string_id & 0x7FF, bak->name); truelight@0: } truelight@0: truelight@0: os = bak->order; truelight@0: // stored shared orders in this special way? truelight@0: if (u) { truelight@0: os[0] = 0xFFFF; truelight@0: os[1] = u->index; truelight@0: return; truelight@0: } truelight@193: truelight@0: sched = v->schedule_ptr; truelight@0: do { truelight@0: ord = *sched++; truelight@0: *os++ = ord; truelight@0: } while (ord != 0); truelight@0: } truelight@0: truelight@0: void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak) truelight@0: { truelight@0: uint16 ord, *os; truelight@0: int ind; truelight@0: truelight@0: if (bak->name[0]) { truelight@0: strcpy((char*)_decode_parameters, bak->name); truelight@0: DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE); truelight@0: } truelight@0: truelight@0: DoCommandP(0, v->index, bak->orderindex|(bak->service_interval<<16) , NULL, CMD_RESTORE_ORDER_INDEX | CMD_ASYNC); truelight@193: truelight@0: os = bak->order; truelight@0: if (os[0] == 0xFFFF) { truelight@0: DoCommandP(0, v->index | os[1]<<16, 0, NULL, CMD_CLONE_ORDER); truelight@0: return; truelight@0: } truelight@0: truelight@0: ind = 0; truelight@0: while ((ord = *os++) != 0) { truelight@0: if (!DoCommandP(0, v->index + (ind << 16), ord, NULL, CMD_INSERT_ORDER | CMD_ASYNC)) truelight@0: break; truelight@0: ind++; truelight@0: } truelight@0: } truelight@0: truelight@0: /* p1 = vehicle truelight@0: * upper 16 bits p2 = service_interval truelight@0: * lower 16 bits p2 = cur_order_index truelight@0: */ truelight@0: int32 CmdRestoreOrderIndex(int x, int y, uint32 flags, uint32 p1, uint32 p2) truelight@0: { truelight@0: // nonsense to update the windows, since, train rebought will have its window deleted truelight@0: if (flags & DC_EXEC) { truelight@0: Vehicle *v = &_vehicles[p1]; truelight@0: v->service_interval = (uint16)(p2>>16); truelight@0: v->cur_order_index = (byte)(p2&0xFFFF); truelight@0: } truelight@0: return 0; truelight@0: } dominik@19: dominik@19: int CheckOrders(Vehicle *v) dominik@19: { dominik@55: if (!_patches.order_review_system) //User doesn't want things to be checked dominik@55: return 0; truelight@193: dominik@55: if ( (_patches.order_review_system == 1) && (v->vehstatus & VS_STOPPED) ) dominik@55: return 0; dominik@19: dominik@55: /* only check every 20 days, so that we don't flood the message log */ dominik@19: if ( ( ( v->day_counter % 20) == 0 ) && (v->owner == _local_player) ) { dominik@55: dominik@55: uint16 order, old_order; dominik@55: int i, n_st, problem_type = -1; dominik@55: Station *st; dominik@55: int message=0; dominik@55: TileIndex required_tile=-1; dominik@55: dominik@55: /* check the order list */ dominik@55: order = v->schedule_ptr[0]; dominik@55: n_st = 0; dominik@55: dominik@55: for (old_order = i = 0; order!=0; i++ ) { dominik@19: order = v->schedule_ptr[i]; dominik@55: if (order == old_order) { dominik@55: problem_type = 2; dominik@55: break; dominik@55: } dominik@55: if ( (order & OT_MASK) == OT_DUMMY ) { dominik@55: problem_type = 1; dominik@55: break; dominik@55: } dominik@19: if ( ( (order & OT_MASK) == OT_GOTO_STATION ) /*&& (order != old_order) */) { dominik@19: //I uncommented this in order not to get two error messages dominik@19: //when two identical entries are in the list dominik@19: n_st++; dominik@55: st = DEREF_STATION(order >> 8); dominik@55: required_tile = GetStationTileForVehicle(v,st); dominik@294: if (!required_tile) problem_type = 3; dominik@19: } dominik@55: old_order = order; //store the old order dominik@19: } dominik@19: dominik@19: //Now, check the last and the first order dominik@19: //as the last order is the end of order marker, jump back 2 dominik@55: if ( (v->schedule_ptr[0] == v->schedule_ptr[i-2]) && ( i-2 != 0 ) ) { dominik@55: problem_type = 2; dominik@55: } truelight@193: celestar@340: if ( (n_st < 2) && (problem_type == -1) ) problem_type = 0; truelight@193: tron@534: SetDParam(0, v->unitnumber); truelight@193: dominik@55: message = (STR_TRAIN_HAS_TOO_FEW_ORDERS) + (((v->type) - VEH_Train) << 2) + problem_type; truelight@193: dominik@55: if (problem_type < 0) return 0; truelight@193: dominik@55: AddNewsItem( dominik@55: message, dominik@55: NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), dominik@55: v->index, dominik@55: 0); dominik@19: } dominik@19: // End of order check dominik@19: dominik@55: return 1; dominik@19: }