order_cmd.c
changeset 555 02df8a1b7f33
parent 543 946badd71033
child 588 03521b270f62
equal deleted inserted replaced
554:a4ba0fbbf018 555:02df8a1b7f33
    13  */
    13  */
    14 int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
    14 int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
    15 {
    15 {
    16 	Vehicle *v = &_vehicles[p1 & 0xFFFF];
    16 	Vehicle *v = &_vehicles[p1 & 0xFFFF];
    17 	int sel = p1 >> 16;
    17 	int sel = p1 >> 16;
    18 	int t;
    18 	Order new_order = UnpackOrder(p2);
    19 
    19 
    20 	if (sel > v->num_orders) return_cmd_error(STR_EMPTY);
    20 	if (sel > v->num_orders) return_cmd_error(STR_EMPTY);
    21 	if (_ptr_to_next_order == endof(_order_array)) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
    21 	if (_ptr_to_next_order == endof(_order_array)) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
    22 	if (v->num_orders >= 40) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
    22 	if (v->num_orders >= 40) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
    23 
    23 
    24 	// for ships, make sure that the station is not too far away from the previous destination.
    24 	// for ships, make sure that the station is not too far away from the previous destination.
    25 	if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) &&
    25 	if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) &&
    26 			sel != 0 && ((t=v->schedule_ptr[sel-1])&OT_MASK) == OT_GOTO_STATION) {
    26 			sel != 0 && v->schedule_ptr[sel - 1].type == OT_GOTO_STATION) {
    27 
    27 
    28 		int dist = GetTileDist(DEREF_STATION(t >> 8)->xy, DEREF_STATION(p2 >> 8)->xy);
    28 		int dist = GetTileDist(
       
    29 			DEREF_STATION(v->schedule_ptr[sel - 1].station)->xy,
       
    30 			DEREF_STATION(new_order.station)->xy
       
    31 		);
    29 		if (dist >= 130)
    32 		if (dist >= 130)
    30 			return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
    33 			return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
    31 	}
    34 	}
    32 
    35 
    33 	if (flags & DC_EXEC) {
    36 	if (flags & DC_EXEC) {
    34 		uint16 *s1, *s2;
    37 		Order *s1;
       
    38 		Order *s2;
    35 		Vehicle *u;
    39 		Vehicle *u;
    36 
    40 
    37 		s1 = &v->schedule_ptr[sel];
    41 		s1 = &v->schedule_ptr[sel];
    38 		s2 = _ptr_to_next_order++;
    42 		s2 = _ptr_to_next_order++;
    39 		do s2[1] = s2[0]; while (--s2 >= s1);
    43 		do s2[1] = s2[0]; while (--s2 >= s1);
    40 		s1[0] = (uint16)p2;
    44 		*s1 = new_order;
    41 
    45 
    42 		s1 = v->schedule_ptr;
    46 		s1 = v->schedule_ptr;
    43 
    47 
    44 		FOR_ALL_VEHICLES(u) {
    48 		FOR_ALL_VEHICLES(u) {
    45 			if (u->type != 0 && u->schedule_ptr != NULL) {
    49 			if (u->type != 0 && u->schedule_ptr != NULL) {
    70 
    74 
    71 	if (flags & DC_EXEC) {
    75 	if (flags & DC_EXEC) {
    72 		DeleteVehicleSchedule(dst);
    76 		DeleteVehicleSchedule(dst);
    73 
    77 
    74 		dst->num_orders = 0;
    78 		dst->num_orders = 0;
    75 		*(dst->schedule_ptr = _ptr_to_next_order++) = 0;
    79 		_ptr_to_next_order->type = OT_NOTHING;
       
    80 		_ptr_to_next_order->flags = 0;
       
    81 		dst->schedule_ptr = _ptr_to_next_order++;
    76 
    82 
    77 		InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
    83 		InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
    78 	}
    84 	}
    79 	return 0;
    85 	return 0;
    80 }
    86 }
    90 	_error_message = STR_EMPTY;
    96 	_error_message = STR_EMPTY;
    91 	if (sel >= v->num_orders)
    97 	if (sel >= v->num_orders)
    92 		return DecloneOrder(v, flags);
    98 		return DecloneOrder(v, flags);
    93 
    99 
    94 	if (flags & DC_EXEC) {
   100 	if (flags & DC_EXEC) {
    95 		uint16 *s1;
   101 		Order *s1 = &v->schedule_ptr[sel];
    96 
       
    97 		s1 = &v->schedule_ptr[sel];
       
    98 
   102 
    99 		// copy all orders to get rid of the hole
   103 		// copy all orders to get rid of the hole
   100 		do s1[0] = s1[1]; while (++s1 != _ptr_to_next_order);
   104 		do s1[0] = s1[1]; while (++s1 != _ptr_to_next_order);
   101 		_ptr_to_next_order--;
   105 		_ptr_to_next_order--;
   102 
   106 
   109 				} else if (s1 == u->schedule_ptr) {// handle shared orders
   113 				} else if (s1 == u->schedule_ptr) {// handle shared orders
   110 					u->num_orders--;
   114 					u->num_orders--;
   111 					if ((byte)sel < u->cur_order_index)
   115 					if ((byte)sel < u->cur_order_index)
   112 						u->cur_order_index--;
   116 						u->cur_order_index--;
   113 
   117 
   114 					if ((byte)sel == u->cur_order_index && (u->next_order&(OT_MASK|OF_NON_STOP)) == (OT_LOADING|OF_NON_STOP))
   118 					if ((byte)sel == u->cur_order_index &&
   115 						u->next_order = OT_LOADING;
   119 							u->current_order.type == OT_LOADING &&
       
   120 							u->current_order.flags & OF_NON_STOP) {
       
   121 						u->current_order.flags = 0;
       
   122 					}
   116 
   123 
   117 					InvalidateWindow(WC_VEHICLE_VIEW, u->index);
   124 					InvalidateWindow(WC_VEHICLE_VIEW, u->index);
   118 					InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
   125 					InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
   119 				}
   126 				}
   120 			}
   127 			}
   137 
   144 
   138 			if (v->type == VEH_Train)
   145 			if (v->type == VEH_Train)
   139 				v->u.rail.days_since_order_progr = 0;
   146 				v->u.rail.days_since_order_progr = 0;
   140 		}
   147 		}
   141 
   148 
   142 		if ((v->next_order&(OT_MASK|OF_NON_STOP)) == (OT_LOADING|OF_NON_STOP))
   149 		if (v->current_order.type == OT_LOADING &&
   143 			v->next_order = OT_LOADING;
   150 				v->current_order.flags & OF_NON_STOP) {
       
   151 			v->current_order.flags = 0;
       
   152 		}
   144 
   153 
   145 		InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
   154 		InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
   146 	}
   155 	}
   147 	return 0;
   156 	return 0;
   148 }
   157 }
   153  */
   162  */
   154 int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
   163 int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
   155 {
   164 {
   156 	Vehicle *v = &_vehicles[p1];
   165 	Vehicle *v = &_vehicles[p1];
   157 	byte sel = (byte)p2;
   166 	byte sel = (byte)p2;
   158 	uint16 *sched;
   167 	Order *sched;
   159 
   168 
   160 	if (sel >= v->num_orders)
   169 	if (sel >= v->num_orders)
   161 		return CMD_ERROR;
   170 		return CMD_ERROR;
   162 
   171 
   163 	sched = &v->schedule_ptr[sel];
   172 	sched = &v->schedule_ptr[sel];
   164 	if (!((*sched & OT_MASK) == OT_GOTO_STATION ||
   173 	if (sched->type != OT_GOTO_STATION &&
   165 			((*sched & OT_MASK) == OT_GOTO_DEPOT &&  (p2>>8) != 1)))
   174 			(sched->type != OT_GOTO_DEPOT || (p2 >> 8) == 1))
   166 		return CMD_ERROR;
   175 		return CMD_ERROR;
   167 
   176 
   168 	if (flags & DC_EXEC) {
   177 	if (flags & DC_EXEC) {
   169 		switch(p2 >> 8) {
   178 		switch (p2 >> 8) {
   170 		case 0: // full load
   179 		case 0: // full load
   171 			*sched ^= OF_FULL_LOAD;
   180 			sched->flags ^= OF_FULL_LOAD;
   172 			if ((*sched & OT_MASK) != OT_GOTO_DEPOT)
   181 			if (sched->type != OT_GOTO_DEPOT) sched->flags &= ~OF_UNLOAD;
   173 				*sched &= ~OF_UNLOAD;
       
   174 			break;
   182 			break;
   175 		case 1: // unload
   183 		case 1: // unload
   176 			*sched ^= OF_UNLOAD;
   184 			sched->flags ^= OF_UNLOAD;
   177 			*sched &= ~OF_FULL_LOAD;
   185 			sched->flags &= ~OF_FULL_LOAD;
   178 			break;
   186 			break;
   179 		case 2: // non stop
   187 		case 2: // non stop
   180 			*sched ^= OF_NON_STOP;
   188 			sched->flags ^= OF_NON_STOP;
   181 			break;
   189 			break;
   182 		}
   190 		}
   183 		sched = v->schedule_ptr;
   191 		sched = v->schedule_ptr;
   184 
   192 
   185 		FOR_ALL_VEHICLES(v) {
   193 		FOR_ALL_VEHICLES(v) {
   245 		if (!(src->owner == _current_player && dst->type == src->type && dst != src))
   253 		if (!(src->owner == _current_player && dst->type == src->type && dst != src))
   246 			return CMD_ERROR;
   254 			return CMD_ERROR;
   247 
   255 
   248 		// let's see what happens with road vehicles
   256 		// let's see what happens with road vehicles
   249 		if (src->type == VEH_Road) {
   257 		if (src->type == VEH_Road) {
   250 			uint16 ord;
   258 			const Order *i;
   251 			int i;
       
   252 			Station *st;
       
   253 			TileIndex required_dst;
   259 			TileIndex required_dst;
   254 
   260 
   255 			for (i=0; (ord = src->schedule_ptr[i]) != 0; i++) {
   261 			for (i = src->schedule_ptr; i->type != OT_NOTHING; ++i) {
   256 				if ( ( ord & OT_MASK ) == OT_GOTO_STATION ) {
   262 				if (i->type == OT_GOTO_STATION) {
   257 					st = DEREF_STATION(ord >> 8);
   263 					const Station *st = DEREF_STATION(i->station);
   258 					required_dst = (dst->cargo_type == CT_PASSENGERS) ? st->bus_tile : st->lorry_tile;
   264 					required_dst = (dst->cargo_type == CT_PASSENGERS) ? st->bus_tile : st->lorry_tile;
   259 					if ( !required_dst )
   265 					if ( !required_dst )
   260 						return CMD_ERROR;
   266 						return CMD_ERROR;
   261 				}
   267 				}
   262 			}
   268 			}
   287 }
   293 }
   288 
   294 
   289 void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak)
   295 void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak)
   290 {
   296 {
   291 	Vehicle *u = IsScheduleShared(v);
   297 	Vehicle *u = IsScheduleShared(v);
   292 	uint16 *sched, ord, *os;
       
   293 
   298 
   294 	bak->orderindex = v->cur_order_index;
   299 	bak->orderindex = v->cur_order_index;
   295 	bak->service_interval = v->service_interval;
   300 	bak->service_interval = v->service_interval;
   296 
   301 
   297 	if ((v->string_id & 0xF800) != 0x7800) {
   302 	if ((v->string_id & 0xF800) != 0x7800) {
   298 		bak->name[0] = 0;
   303 		bak->name[0] = 0;
   299 	} else {
   304 	} else {
   300 		GetName(v->string_id & 0x7FF, bak->name);
   305 		GetName(v->string_id & 0x7FF, bak->name);
   301 	}
   306 	}
   302 
   307 
   303 	os = bak->order;
       
   304 	// stored shared orders in this special way?
   308 	// stored shared orders in this special way?
   305 	if (u) {
   309 	if (u != NULL) {
   306 		os[0] = 0xFFFF;
   310 		bak->clone = u->index;
   307 		os[1] = u->index;
   311 	} else {
   308 		return;
   312 		Order *sched = v->schedule_ptr;
   309 	}
   313 		Order *os = bak->order;
   310 
   314 
   311 	sched = v->schedule_ptr;
   315 		bak->clone = INVALID_VEHICLE;
   312 	do {
   316 
   313 		ord = *sched++;
   317 		do {
   314 		*os++ = ord;
   318 			*os++ = *sched++;
   315 	} while (ord != 0);
   319 		} while (sched->type != OT_NOTHING);
       
   320 	}
   316 }
   321 }
   317 
   322 
   318 void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
   323 void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
   319 {
   324 {
   320 	uint16 ord, *os;
   325 	int i;
   321 	int ind;
       
   322 
   326 
   323 	if (bak->name[0]) {
   327 	if (bak->name[0]) {
   324 		strcpy((char*)_decode_parameters, bak->name);
   328 		strcpy((char*)_decode_parameters, bak->name);
   325 		DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
   329 		DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
   326 	}
   330 	}
   327 
   331 
   328 	DoCommandP(0, v->index, bak->orderindex|(bak->service_interval<<16) , NULL, CMD_RESTORE_ORDER_INDEX);
   332 	DoCommandP(0, v->index, bak->orderindex|(bak->service_interval<<16) , NULL, CMD_RESTORE_ORDER_INDEX);
   329 
   333 
   330 	os = bak->order;
   334 	if (bak->clone != INVALID_VEHICLE) {
   331 	if (os[0] == 0xFFFF) {
   335 		DoCommandP(0, v->index | bak->clone << 16, 0, NULL, CMD_CLONE_ORDER);
   332 		DoCommandP(0, v->index | os[1]<<16, 0, NULL, CMD_CLONE_ORDER);
       
   333 		return;
   336 		return;
   334 	}
   337 	}
   335 
   338 
   336 	// CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
   339 	// CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
   337 	//  order number is one more then the current amount of orders, and because
   340 	//  order number is one more then the current amount of orders, and because
   338 	//  in network the commands are queued before send, the second insert always
   341 	//  in network the commands are queued before send, the second insert always
   339 	//  fails in test mode. By bypassing the test-mode, that no longer is a problem.
   342 	//  fails in test mode. By bypassing the test-mode, that no longer is a problem.
   340 	ind = 0;
   343 	for (i = 0; bak->order[i].type != OT_NOTHING; ++i)
   341 	while ((ord = *os++) != 0) {
   344 		if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
   342 		if (!DoCommandP(0, v->index + (ind << 16), ord, NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
       
   343 			break;
   345 			break;
   344 		ind++;
       
   345 	}
       
   346 }
   346 }
   347 
   347 
   348 /*	p1 = vehicle
   348 /*	p1 = vehicle
   349  *	upper 16 bits p2 = service_interval
   349  *	upper 16 bits p2 = service_interval
   350  *	lower 16 bits p2 = cur_order_index
   350  *	lower 16 bits p2 = cur_order_index
   368 	if ( (_patches.order_review_system == 1) && (v->vehstatus & VS_STOPPED) )
   368 	if ( (_patches.order_review_system == 1) && (v->vehstatus & VS_STOPPED) )
   369 		return 0;
   369 		return 0;
   370 
   370 
   371 	/* only check every 20 days, so that we don't flood the message log */
   371 	/* only check every 20 days, so that we don't flood the message log */
   372 	if ( ( ( v->day_counter % 20) == 0 ) && (v->owner == _local_player) ) {
   372 	if ( ( ( v->day_counter % 20) == 0 ) && (v->owner == _local_player) ) {
   373 
   373 		Order order;
   374 		uint16 order, old_order;
   374 		Order old_order;
   375 		int i, n_st, problem_type = -1;
   375 		int i, n_st, problem_type = -1;
   376 		Station *st;
   376 		Station *st;
   377 		int message=0;
   377 		int message=0;
   378 		TileIndex required_tile=-1;
   378 		TileIndex required_tile=-1;
   379 
   379 
   380 		/* check the order list */
   380 		/* check the order list */
   381 		order = v->schedule_ptr[0];
   381 		order = v->schedule_ptr[0];
   382 		n_st = 0;
   382 		n_st = 0;
   383 
   383 
   384  		for (old_order = i = 0; order!=0; i++ ) {
   384 		old_order.type = OT_NOTHING;
       
   385 		old_order.flags = 0;
       
   386 		for (i = 0; order.type != OT_NOTHING; i++) {
   385 			order = v->schedule_ptr[i];
   387 			order = v->schedule_ptr[i];
   386 			if (order == old_order) {
   388 			if (order.type == old_order.type &&
       
   389 					order.flags == old_order.flags &&
       
   390 					order.station == old_order.station) {
   387 				problem_type = 2;
   391 				problem_type = 2;
   388 				break;
   392 				break;
   389 			}
   393 			}
   390 			if ( (order & OT_MASK) == OT_DUMMY ) {
   394 			if (order.type == OT_DUMMY) {
   391 				problem_type = 1;
   395 				problem_type = 1;
   392 				break;
   396 				break;
   393 			}
   397 			}
   394 			if ( ( (order & OT_MASK) == OT_GOTO_STATION ) /*&& (order != old_order) */) {
   398 			if (order.type == OT_GOTO_STATION /*&& (order != old_order) */) {
   395 				//I uncommented this in order not to get two error messages
   399 				//I uncommented this in order not to get two error messages
   396 				//when two identical entries are in the list
   400 				//when two identical entries are in the list
   397 				n_st++;
   401 				n_st++;
   398 				st = DEREF_STATION(order >> 8);
   402 				st = DEREF_STATION(order.station);
   399 				required_tile = GetStationTileForVehicle(v,st);
   403 				required_tile = GetStationTileForVehicle(v,st);
   400 				if (!required_tile) problem_type = 3;
   404 				if (!required_tile) problem_type = 3;
   401 			}
   405 			}
   402 			old_order = order; //store the old order
   406 			old_order = order; //store the old order
   403 		}
   407 		}
   404 
   408 
   405 		//Now, check the last and the first order
   409 		//Now, check the last and the first order
   406 		//as the last order is the end of order marker, jump back 2
   410 		//as the last order is the end of order marker, jump back 2
   407 		if ( (v->schedule_ptr[0] == v->schedule_ptr[i-2]) && ( i-2 != 0 ) ) {
   411 		if (i > 2 &&
       
   412 				v->schedule_ptr[0].type == v->schedule_ptr[i - 2].type &&
       
   413 				v->schedule_ptr[0].flags == v->schedule_ptr[i - 2].flags &&
       
   414 				v->schedule_ptr[0].station == v->schedule_ptr[i - 2].station)
   408 			problem_type = 2;
   415 			problem_type = 2;
   409 		}
       
   410 
   416 
   411 		if ( (n_st < 2) && (problem_type == -1) ) problem_type = 0;
   417 		if ( (n_st < 2) && (problem_type == -1) ) problem_type = 0;
   412 
   418 
   413 		SetDParam(0, v->unitnumber);
   419 		SetDParam(0, v->unitnumber);
   414 
   420