summaryrefslogtreecommitdiff
path: root/src/order_cmd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/order_cmd.cpp')
-rw-r--r--src/order_cmd.cpp177
1 files changed, 171 insertions, 6 deletions
diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp
index 7682ba660..9a0826871 100644
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -93,6 +93,13 @@ void Order::MakeDummy()
this->flags = 0;
}
+void Order::MakeConditional(VehicleOrderID order)
+{
+ this->type = OT_CONDITIONAL;
+ this->flags = 0;
+ this->dest = order;
+}
+
void Order::SetRefit(CargoID cargo, byte subtype)
{
this->refit_cargo = cargo;
@@ -427,6 +434,14 @@ CommandCost CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
break;
}
+ case OT_CONDITIONAL: {
+ if (!IsPlayerBuildableVehicleType(v)) return CMD_ERROR;
+
+ VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
+ if (skip_to >= v->num_orders) return CMD_ERROR;
+ if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) return CMD_ERROR;
+ } break;
+
default: return CMD_ERROR;
}
@@ -512,6 +527,22 @@ CommandCost CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
InvalidateVehicleOrder(u);
}
+ /* As we insert an order, the order to skip to will be 'wrong'. */
+ VehicleOrderID cur_order_id = 0;
+ Order *order;
+ FOR_VEHICLE_ORDERS(v, order) {
+ if (order->IsType(OT_CONDITIONAL)) {
+ VehicleOrderID order_id = order->GetConditionSkipToOrder();
+ if (order_id >= sel_ord) {
+ order->SetConditionSkipToOrder(order_id + 1);
+ }
+ if (order_id == cur_order_id) {
+ order->SetConditionSkipToOrder((order_id + 1) % v->num_orders);
+ }
+ }
+ cur_order_id++;
+ }
+
/* Make sure to rebuild the whole list */
RebuildVehicleLists();
}
@@ -625,6 +656,21 @@ CommandCost CmdDeleteOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
InvalidateVehicleOrder(u);
}
+ /* As we delete an order, the order to skip to will be 'wrong'. */
+ VehicleOrderID cur_order_id = 0;
+ FOR_VEHICLE_ORDERS(v, order) {
+ if (order->IsType(OT_CONDITIONAL)) {
+ VehicleOrderID order_id = order->GetConditionSkipToOrder();
+ if (order_id >= sel_ord) {
+ order->SetConditionSkipToOrder(max(order_id - 1, 0));
+ }
+ if (order_id == cur_order_id) {
+ order->SetConditionSkipToOrder((order_id + 1) % v->num_orders);
+ }
+ }
+ cur_order_id++;
+ }
+
RebuildVehicleLists();
}
@@ -746,6 +792,22 @@ CommandCost CmdMoveOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
InvalidateVehicleOrder(u);
}
+ /* As we move an order, the order to skip to will be 'wrong'. */
+ Order *order;
+ FOR_VEHICLE_ORDERS(v, order) {
+ if (order->IsType(OT_CONDITIONAL)) {
+ VehicleOrderID order_id = order->GetConditionSkipToOrder();
+ if (order_id == moving_order) {
+ order_id = target_order;
+ } else if(order_id > moving_order && order_id <= target_order) {
+ order_id--;
+ } else if(order_id < moving_order && order_id >= target_order) {
+ order_id++;
+ }
+ order->SetConditionSkipToOrder(order_id);
+ }
+ }
+
/* Make sure to rebuild the whole list */
RebuildVehicleLists();
}
@@ -762,16 +824,17 @@ CommandCost CmdMoveOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
* the order will be inserted before that one
* only the first 8 bits used currently (bit 16 - 23) (max 255)
* @param p2 various bitstuffed elements
- * - p2 = (bit 0 - 1) - what data to modify (@see ModifyOrderFlags)
- * - p2 = (bit 2 - 5) - the data to modify
+ * - p2 = (bit 0 - 3) - what data to modify (@see ModifyOrderFlags)
+ * - p2 = (bit 4 - 15) - the data to modify
*/
CommandCost CmdModifyOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
VehicleOrderID sel_ord = GB(p1, 16, 16); // XXX - automatically truncated to 8 bits.
VehicleID veh = GB(p1, 0, 16);
- ModifyOrderFlags mof = (ModifyOrderFlags)GB(p2, 0, 2);
- uint8 data = GB(p2, 2, 4);
+ ModifyOrderFlags mof = (ModifyOrderFlags)GB(p2, 0, 4);
+ uint16 data = GB(p2, 4, 11);
+ if (mof >= MOF_END) return CMD_ERROR;
if (!IsValidVehicleID(veh)) return CMD_ERROR;
Vehicle *v = GetVehicle(veh);
@@ -783,22 +846,28 @@ CommandCost CmdModifyOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
Order *order = GetVehicleOrder(v, sel_ord);
switch (order->GetType()) {
case OT_GOTO_STATION:
- if (mof == MOF_DEPOT_ACTION || GetStation(order->GetDestination())->IsBuoy()) return CMD_ERROR;
+ if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE || GetStation(order->GetDestination())->IsBuoy()) return CMD_ERROR;
break;
case OT_GOTO_DEPOT:
- if (mof == MOF_UNLOAD || mof == MOF_LOAD) return CMD_ERROR;
+ if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
break;
case OT_GOTO_WAYPOINT:
if (mof != MOF_NON_STOP) return CMD_ERROR;
break;
+ case OT_CONDITIONAL:
+ if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE) return CMD_ERROR;
+ break;
+
default:
return CMD_ERROR;
}
switch (mof) {
+ default: NOT_REACHED();
+
case MOF_NON_STOP:
if (data >= ONSF_END) return CMD_ERROR;
if (data == order->GetNonStopType()) return CMD_ERROR;
@@ -819,6 +888,36 @@ CommandCost CmdModifyOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
case MOF_DEPOT_ACTION:
if (data != 0) return CMD_ERROR;
break;
+
+ case MOF_COND_VARIABLE:
+ if (data >= OCV_END) return CMD_ERROR;
+ break;
+
+ case MOF_COND_COMPARATOR:
+ if (data >= OCC_END) return CMD_ERROR;
+ switch (order->GetConditionVariable()) {
+ case OCV_REQUIRES_SERVICE:
+ if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
+ break;
+
+ default:
+ if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
+ break;
+ }
+ break;
+
+ case MOF_COND_VALUE:
+ switch (order->GetConditionVariable()) {
+ case OCV_LOAD_PERCENTAGE:
+ case OCV_RELIABILITY:
+ if (data > 100) return CMD_ERROR;
+ break;
+
+ default:
+ if (data > 2047) return CMD_ERROR;
+ break;
+ }
+ break;
}
if (flags & DC_EXEC) {
@@ -846,6 +945,33 @@ CommandCost CmdModifyOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() ^ ODTFB_SERVICE));
break;
+ case MOF_COND_VARIABLE: {
+ order->SetConditionVariable((OrderConditionVariable)data);
+
+ OrderConditionComparator occ = order->GetConditionComparator();
+ switch (order->GetConditionVariable()) {
+ case OCV_REQUIRES_SERVICE:
+ if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
+ break;
+
+ case OCV_LOAD_PERCENTAGE:
+ case OCV_RELIABILITY:
+ if (order->GetConditionValue() > 100) order->SetConditionValue(100);
+ /* FALL THROUGH */
+ default:
+ if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
+ break;
+ }
+ } break;
+
+ case MOF_COND_COMPARATOR:
+ order->SetConditionComparator((OrderConditionComparator)data);
+ break;
+
+ case MOF_COND_VALUE:
+ order->SetConditionValue(data);
+ break;
+
default: NOT_REACHED();
}
@@ -1417,6 +1543,24 @@ static bool CheckForValidOrders(const Vehicle *v)
}
/**
+ * Compare the variable and value based on the given comparator.
+ */
+static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
+{
+ switch (occ) {
+ case OCC_EQUALS: return variable == value;
+ case OCC_NOT_EQUALS: return variable != value;
+ case OCC_LESS_THAN: return variable < value;
+ case OCC_LESS_EQUALS: return variable <= value;
+ case OCC_MORE_THAN: return variable > value;
+ case OCC_MORE_EQUALS: return variable >= value;
+ case OCC_IS_TRUE: return variable != 0;
+ case OCC_IS_FALSE: return variable == 0;
+ default: NOT_REACHED();
+ }
+}
+
+/**
* Handle the orders of a vehicle and determine the next place
* to go to if needed.
* @param v the vehicle to do this for.
@@ -1551,6 +1695,27 @@ bool ProcessOrders(Vehicle *v)
v->dest_tile = GetWaypoint(order->GetDestination())->xy;
break;
+ case OT_CONDITIONAL: {
+ bool skip_order = false;
+ OrderConditionComparator occ = order->GetConditionComparator();
+ uint16 value = order->GetConditionValue();
+
+ switch (order->GetConditionVariable()) {
+ case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
+ case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, v->reliability * 100 >> 16, value); break;
+ case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed(), value); break;
+ case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / 366, value); break;
+ case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
+ default: NOT_REACHED();
+ }
+ UpdateVehicleTimetable(v, true);
+ if (skip_order) {
+ v->cur_order_index = order->GetConditionSkipToOrder();
+ } else {
+ v->cur_order_index++;
+ }
+ } return false;
+
default:
v->dest_tile = 0;
return false;