Changeset - r18287:f964c590dce6
[Not reviewed]
master
0 1 0
yexo - 13 years ago 2011-11-08 15:43:34
yexo@openttd.org
(svn r23133) -Fix [FS#4823]: AIOrder didn't handle implicit orders correctly in all cases
1 file changed with 59 insertions and 20 deletions:
0 comments (0 inline, 0 general)
src/ai/api/ai_order.cpp
Show inline comments
 
@@ -73,12 +73,37 @@ static const Order *ResolveOrder(Vehicle
 
		order = order->next;
 
		while (order->GetType() == OT_IMPLICIT) order = order->next;
 
	}
 
	return order;
 
}
 

	
 
/**
 
 * Convert an AIOrder::OrderPosition (which is the manual order index) to an order index
 
 * as expected by the OpenTTD commands.
 
 * @param order_position The OrderPosition to convert.
 
 * @return An OpenTTD-internal index for the same order.
 
 */
 
static const int AIOrderPositionToRealOrderPosition(VehicleID vehicle_id, AIOrder::OrderPosition order_position)
 
{
 
	const Vehicle *v = ::Vehicle::Get(vehicle_id);
 
	if (order_position == v->GetNumManualOrders()) return v->GetNumOrders();
 

	
 
	assert(AIOrder::IsValidVehicleOrder(vehicle_id, order_position));
 

	
 
	int res = (int)order_position;
 
	const Order *order = v->orders.list->GetFirstOrder();
 
	for (; order->GetType() == OT_IMPLICIT; order = order->next) res++;
 
	while (order_position > 0) {
 
		order_position = (AIOrder::OrderPosition)(order_position - 1);
 
		order = order->next;
 
		for (; order->GetType() == OT_IMPLICIT; order = order->next) res++;
 
	}
 

	
 
	return res;
 
}
 

	
 
/* static */ bool AIOrder::IsGotoStationOrder(VehicleID vehicle_id, OrderPosition order_position)
 
{
 
	if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
 

	
 
	const Order *order = ::ResolveOrder(vehicle_id, order_position);
 
	return order != NULL && order->GetType() == OT_GOTO_STATION;
 
@@ -102,22 +127,22 @@ static const Order *ResolveOrder(Vehicle
 

	
 
/* static */ bool AIOrder::IsConditionalOrder(VehicleID vehicle_id, OrderPosition order_position)
 
{
 
	if (order_position == ORDER_CURRENT) return false;
 
	if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
 

	
 
	const Order *order = Vehicle::Get(vehicle_id)->GetOrder(order_position);
 
	const Order *order = ::Vehicle::Get(vehicle_id)->GetOrder(AIOrderPositionToRealOrderPosition(order_position));
 
	return order->GetType() == OT_CONDITIONAL;
 
}
 

	
 
/* static */ bool AIOrder::IsVoidOrder(VehicleID vehicle_id, OrderPosition order_position)
 
{
 
	if (order_position == ORDER_CURRENT) return false;
 
	if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
 

	
 
	const Order *order = Vehicle::Get(vehicle_id)->GetOrder(order_position);
 
	const Order *order = ::ResolveOrder(vehicle_id, order_position);
 
	return order->GetType() == OT_DUMMY;
 
}
 

	
 
/* static */ bool AIOrder::IsRefitOrder(VehicleID vehicle_id, OrderPosition order_position)
 
{
 
	if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
 
@@ -353,80 +378,86 @@ static const Order *ResolveOrder(Vehicle
 
/* static */ bool AIOrder::SetOrderCondition(VehicleID vehicle_id, OrderPosition order_position, OrderCondition condition)
 
{
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
 
	EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
 
	EnforcePrecondition(false, condition >= OC_LOAD_PERCENTAGE && condition <= OC_REMAINING_LIFETIME);
 

	
 
	return AIObject::DoCommand(0, vehicle_id | (order_position << 20), MOF_COND_VARIABLE | (condition << 4), CMD_MODIFY_ORDER);
 
	int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
 
	return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), MOF_COND_VARIABLE | (condition << 4), CMD_MODIFY_ORDER);
 
}
 

	
 
/* static */ bool AIOrder::SetOrderCompareFunction(VehicleID vehicle_id, OrderPosition order_position, CompareFunction compare)
 
{
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
 
	EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
 
	EnforcePrecondition(false, compare >= CF_EQUALS && compare <= CF_IS_FALSE);
 

	
 
	return AIObject::DoCommand(0, vehicle_id | (order_position << 20), MOF_COND_COMPARATOR | (compare << 4), CMD_MODIFY_ORDER);
 
	int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
 
	return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), MOF_COND_COMPARATOR | (compare << 4), CMD_MODIFY_ORDER);
 
}
 

	
 
/* static */ bool AIOrder::SetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position, int32 value)
 
{
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
 
	EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
 
	EnforcePrecondition(false, value >= 0 && value < 2048);
 
	if (GetOrderCondition(vehicle_id, order_position) == OC_MAX_SPEED) value = value * 10 / 16;
 

	
 
	return AIObject::DoCommand(0, vehicle_id | (order_position << 20), MOF_COND_VALUE | (value << 4), CMD_MODIFY_ORDER);
 
	int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
 
	return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), MOF_COND_VALUE | (value << 4), CMD_MODIFY_ORDER);
 
}
 

	
 
/* static */ bool AIOrder::SetStopLocation(VehicleID vehicle_id, OrderPosition order_position, StopLocation stop_location)
 
{
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
 
	EnforcePrecondition(false, AIVehicle::GetVehicleType(vehicle_id) == AIVehicle::VT_RAIL);
 
	EnforcePrecondition(false, IsGotoStationOrder(vehicle_id, order_position));
 
	EnforcePrecondition(false, stop_location >= STOPLOCATION_NEAR && stop_location <= STOPLOCATION_FAR);
 

	
 
	uint32 p1 = vehicle_id | (order_position << 20);
 
	order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
 

	
 
	int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
 
	uint32 p1 = vehicle_id | (order_pos << 20);
 
	uint32 p2 = MOF_STOP_LOCATION | (stop_location << 4);
 
	return AIObject::DoCommand(0, p1, p2, CMD_MODIFY_ORDER);
 
}
 

	
 
/* static */ bool AIOrder::SetOrderRefit(VehicleID vehicle_id, OrderPosition order_position, CargoID refit_cargo)
 
{
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
 
	EnforcePrecondition(false, IsGotoStationOrder(vehicle_id, order_position) || (IsGotoDepotOrder(vehicle_id, order_position) && refit_cargo != CT_AUTO_REFIT));
 
	EnforcePrecondition(false, AICargo::IsValidCargo(refit_cargo) || refit_cargo == CT_AUTO_REFIT || refit_cargo == CT_NO_REFIT);
 

	
 
	uint32 p1 = vehicle_id;
 
	uint32 p2 = refit_cargo | AIOrder::ResolveOrderPosition(vehicle_id, order_position) << 16;
 
	uint32 p2 = refit_cargo | AIOrderPositionToRealOrderPosition(AIOrder::ResolveOrderPosition(vehicle_id, order_position)) << 16;
 
	return AIObject::DoCommand(0, p1, p2, CMD_ORDER_REFIT);
 
}
 

	
 
/* static */ bool AIOrder::AppendOrder(VehicleID vehicle_id, TileIndex destination, AIOrderFlags order_flags)
 
{
 
	EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
 
	EnforcePrecondition(false, AreOrderFlagsValid(destination, order_flags));
 

	
 
	return InsertOrder(vehicle_id, (AIOrder::OrderPosition)::Vehicle::Get(vehicle_id)->GetNumOrders(), destination, order_flags);
 
	return InsertOrder(vehicle_id, (AIOrder::OrderPosition)::Vehicle::Get(vehicle_id)->GetNumManualOrders(), destination, order_flags);
 
}
 

	
 
/* static */ bool AIOrder::AppendConditionalOrder(VehicleID vehicle_id, OrderPosition jump_to)
 
{
 
	EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to));
 

	
 
	return InsertConditionalOrder(vehicle_id, (AIOrder::OrderPosition)::Vehicle::Get(vehicle_id)->GetNumOrders(), jump_to);
 
	return InsertConditionalOrder(vehicle_id, (AIOrder::OrderPosition)::Vehicle::Get(vehicle_id)->GetNumManualOrders(), jump_to);
 
}
 

	
 
/* static */ bool AIOrder::InsertOrder(VehicleID vehicle_id, OrderPosition order_position, TileIndex destination, AIOrder::AIOrderFlags order_flags)
 
{
 
	/* IsValidVehicleOrder is not good enough because it does not allow appending. */
 
	if (order_position == ORDER_CURRENT) order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
 

	
 
	EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
 
	EnforcePrecondition(false, order_position >= 0 && order_position <= ::Vehicle::Get(vehicle_id)->GetNumOrders());
 
	EnforcePrecondition(false, order_position >= 0 && order_position <= ::Vehicle::Get(vehicle_id)->GetNumManualOrders());
 
	EnforcePrecondition(false, AreOrderFlagsValid(destination, order_flags));
 

	
 
	Order order;
 
	OrderType ot = (order_flags & AIOF_GOTO_NEAREST_DEPOT) ? OT_GOTO_DEPOT : ::GetOrderTypeByTile(destination);
 
	switch (ot) {
 
		case OT_GOTO_DEPOT: {
 
@@ -464,45 +495,50 @@ static const Order *ResolveOrder(Vehicle
 
		default:
 
			return false;
 
	}
 

	
 
	order.SetNonStopType((OrderNonStopFlags)GB(order_flags, 0, 2));
 

	
 
	return AIObject::DoCommand(0, vehicle_id | (order_position << 20), order.Pack(), CMD_INSERT_ORDER);
 
	int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
 
	return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), order.Pack(), CMD_INSERT_ORDER);
 
}
 

	
 
/* static */ bool AIOrder::InsertConditionalOrder(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to)
 
{
 
	/* IsValidVehicleOrder is not good enough because it does not allow appending. */
 
	if (order_position == ORDER_CURRENT) order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
 

	
 
	EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to));
 
	EnforcePrecondition(false, order_position >= 0 && order_position <= ::Vehicle::Get(vehicle_id)->GetNumManualOrders());
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to) && jump_to != ORDER_CURRENT);
 

	
 
	Order order;
 
	order.MakeConditional(jump_to);
 

	
 
	return AIObject::DoCommand(0, vehicle_id | (order_position << 20), order.Pack(), CMD_INSERT_ORDER);
 
	int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
 
	return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), order.Pack(), CMD_INSERT_ORDER);
 
}
 

	
 
/* static */ bool AIOrder::RemoveOrder(VehicleID vehicle_id, OrderPosition order_position)
 
{
 
	order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
 

	
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
 

	
 
	return AIObject::DoCommand(0, vehicle_id, order_position, CMD_DELETE_ORDER);
 
	int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
 
	return AIObject::DoCommand(0, vehicle_id, order_pos, CMD_DELETE_ORDER);
 
}
 

	
 
/* static */ bool AIOrder::SkipToOrder(VehicleID vehicle_id, OrderPosition next_order)
 
{
 
	next_order = AIOrder::ResolveOrderPosition(vehicle_id, next_order);
 

	
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, next_order));
 

	
 
	return AIObject::DoCommand(0, vehicle_id, next_order, CMD_SKIP_TO_ORDER);
 
	int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, next_order);
 
	return AIObject::DoCommand(0, vehicle_id, order_pos, CMD_SKIP_TO_ORDER);
 
}
 

	
 
/**
 
 * Callback handler as SetOrderFlags possibly needs multiple DoCommand calls
 
 * to be able to set all order flags correctly. As we need to wait till the
 
 * command has completed before we know the next bits to change we need to
 
@@ -533,37 +569,38 @@ static void _DoCommandReturnSetOrderFlag
 
	order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
 

	
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
 
	EnforcePrecondition(false, AreOrderFlagsValid(GetOrderDestination(vehicle_id, order_position), order_flags));
 

	
 
	const Order *order = ::ResolveOrder(vehicle_id, order_position);
 
	int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
 

	
 
	AIOrderFlags current = GetOrderFlags(vehicle_id, order_position);
 

	
 
	EnforcePrecondition(false, (order_flags & AIOF_GOTO_NEAREST_DEPOT) == (current & AIOF_GOTO_NEAREST_DEPOT));
 

	
 
	if ((current & AIOF_NON_STOP_FLAGS) != (order_flags & AIOF_NON_STOP_FLAGS)) {
 
		return AIObject::DoCommand(0, vehicle_id | (order_position << 20), (order_flags & AIOF_NON_STOP_FLAGS) << 4 | MOF_NON_STOP, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
 
		return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & AIOF_NON_STOP_FLAGS) << 4 | MOF_NON_STOP, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
 
	}
 

	
 
	switch (order->GetType()) {
 
		case OT_GOTO_DEPOT:
 
			if ((current & AIOF_DEPOT_FLAGS) != (order_flags & AIOF_DEPOT_FLAGS)) {
 
				uint data = DA_ALWAYS_GO;
 
				if (order_flags & AIOF_SERVICE_IF_NEEDED) data = DA_SERVICE;
 
				if (order_flags & AIOF_STOP_IN_DEPOT) data = DA_STOP;
 
				return AIObject::DoCommand(0, vehicle_id | (order_position << 20), (data << 4) | MOF_DEPOT_ACTION, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
 
				return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), (data << 4) | MOF_DEPOT_ACTION, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
 
			}
 
			break;
 

	
 
		case OT_GOTO_STATION:
 
			if ((current & AIOF_UNLOAD_FLAGS) != (order_flags & AIOF_UNLOAD_FLAGS)) {
 
				return AIObject::DoCommand(0, vehicle_id | (order_position << 20), (order_flags & AIOF_UNLOAD_FLAGS) << 2 | MOF_UNLOAD, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
 
				return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & AIOF_UNLOAD_FLAGS) << 2 | MOF_UNLOAD, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
 
			}
 
			if ((current & AIOF_LOAD_FLAGS) != (order_flags & AIOF_LOAD_FLAGS)) {
 
				return AIObject::DoCommand(0, vehicle_id | (order_position << 20), (order_flags & AIOF_LOAD_FLAGS) >> 1 | MOF_LOAD, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
 
				return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & AIOF_LOAD_FLAGS) >> 1 | MOF_LOAD, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
 
			}
 
			break;
 

	
 
		default: break;
 
	}
 

	
 
@@ -588,13 +625,15 @@ static void _DoCommandReturnSetOrderFlag
 
	order_position_move   = AIOrder::ResolveOrderPosition(vehicle_id, order_position_move);
 
	order_position_target = AIOrder::ResolveOrderPosition(vehicle_id, order_position_target);
 

	
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_move));
 
	EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_target));
 

	
 
	return AIObject::DoCommand(0, vehicle_id, order_position_move | (order_position_target << 16), CMD_MOVE_ORDER);
 
	int order_pos_move = AIOrderPositionToRealOrderPosition(vehicle_id, order_position_move);
 
	int order_pos_target = AIOrderPositionToRealOrderPosition(vehicle_id, order_position_target);
 
	return AIObject::DoCommand(0, vehicle_id, order_pos_move | (order_pos_target << 16), CMD_MOVE_ORDER);
 
}
 

	
 
/* static */ bool AIOrder::CopyOrders(VehicleID vehicle_id, VehicleID main_vehicle_id)
 
{
 
	EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
 
	EnforcePrecondition(false, AIVehicle::IsValidVehicle(main_vehicle_id));
0 comments (0 inline, 0 general)