From 83062be4e08b2bc78a33646d911d10c22a3d739c Mon Sep 17 00:00:00 2001 From: rubidium Date: Fri, 18 Nov 2011 21:10:44 +0000 Subject: [PATCH] (svn r23256) [1.1] -Backport from trunk: - Fix: [Squirrel] replace custom qsort by std::sort to fix stack overflow [FS#4830] (r23190, r23187, r23186) - Fix: Do not display railway fences between track and waypoints [FS#4627] (r23163) - Fix: [NoAI] AIOrder didn't handle implicit orders correctly in all cases [FS#4823] (r23133) --- src/3rdparty/squirrel/squirrel/sqbaselib.cpp | 57 ++++++--------- src/ai/api/ai_order.cpp | 77 +++++++++++++++----- src/rail_cmd.cpp | 8 +- 3 files changed, 85 insertions(+), 57 deletions(-) diff --git a/src/3rdparty/squirrel/squirrel/sqbaselib.cpp b/src/3rdparty/squirrel/squirrel/sqbaselib.cpp index aa0f67ed2f..d9074d3174 100644 --- a/src/3rdparty/squirrel/squirrel/sqbaselib.cpp +++ b/src/3rdparty/squirrel/squirrel/sqbaselib.cpp @@ -1,6 +1,9 @@ /* see copyright notice in squirrel.h */ +/* Needs to be first due to a squirrel header defining type() and type() + * being used in some versions of the headers included by algorithm. */ +#include #include "sqpcheader.h" #include "sqvm.h" #include "sqstring.h" @@ -484,7 +487,7 @@ static SQInteger array_resize(HSQUIRRELVM v) //QSORT ala Sedgewick -bool _qsort_compare(HSQUIRRELVM v,SQObjectPtr &arr,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret) +bool _qsort_compare(HSQUIRRELVM v,SQObjectPtr &arr,const SQObjectPtr &a,const SQObjectPtr &b,SQInteger func,SQInteger &ret) { if(func < 0) { if(!v->ObjCmp(a,b,ret)) return false; @@ -506,40 +509,26 @@ bool _qsort_compare(HSQUIRRELVM v,SQObjectPtr &arr,SQObjectPtr &a,SQObjectPtr &b } return true; } -//QSORT ala Sedgewick -bool _qsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger func) +struct qsort_cmp { - SQInteger i, j; - SQArray *a=_array(arr); - SQObjectPtr pivot,t; - if( l < r ){ - pivot = a->_values[l]; - i = l; j = r+1; - while(1){ - SQInteger ret; - do { - ++i; - if(i > r) break; - if(!_qsort_compare(v,arr,a->_values[i],pivot,func,ret)) - return false; - } while( ret <= 0); - do { - --j; - if ( j < 0 ) { - v->Raise_Error( _SC("Invalid qsort, probably compare function defect") ); - return false; - } - if(!_qsort_compare(v,arr,a->_values[j],pivot,func,ret)) - return false; - } - while( ret > 0 ); - if( i >= j ) break; - t = a->_values[i]; a->_values[i] = a->_values[j]; a->_values[j] = t; - } - t = a->_values[l]; a->_values[l] = a->_values[j]; a->_values[j] = t; - if(!_qsort( v, arr, l, j-1,func)) return false; - if(!_qsort( v, arr, j+1, r,func)) return false; + HSQUIRRELVM v; + SQInteger func; + bool operator() (const SQObjectPtr &a, const SQObjectPtr &b) const + { + SQInteger res; + SQObjectPtr dummy; + if (!_qsort_compare(v, dummy, a, b, func, res)) return false; + return res < 0; } +}; + +bool _qsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger func) +{ + SQArray *a=_array(arr); + qsort_cmp cur_cmp; + cur_cmp.v = v; + cur_cmp.func = func; + std::sort(a->_values._vals, a->_values._vals + a->Size(), cur_cmp); return true; } @@ -550,7 +539,7 @@ static SQInteger array_sort(HSQUIRRELVM v) SQObject &funcobj = stack_get(v,2); if(_array(o)->Size() > 1) { if(type(funcobj) == OT_CLOSURE || type(funcobj) == OT_NATIVECLOSURE) func = 2; - if(!_qsort(v, o, 0, _array(o)->Size()-1, func)) + if(!_qsort(v, o, func)) return SQ_ERROR; } diff --git a/src/ai/api/ai_order.cpp b/src/ai/api/ai_order.cpp index 4bad055724..5973151bb7 100644 --- a/src/ai/api/ai_order.cpp +++ b/src/ai/api/ai_order.cpp @@ -75,6 +75,31 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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 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; @@ -104,7 +129,7 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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(vehicle_id, order_position)); return order->GetType() == OT_CONDITIONAL; } @@ -113,7 +138,7 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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; } @@ -337,7 +362,8 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position)); EnforcePrecondition(false, condition >= OC_LOAD_PERCENTAGE && condition <= OC_UNCONDITIONALLY); - 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) @@ -346,7 +372,8 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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) @@ -356,7 +383,8 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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) @@ -366,7 +394,10 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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); } @@ -376,7 +407,7 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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) @@ -384,7 +415,7 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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) @@ -393,7 +424,7 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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; @@ -437,7 +468,8 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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) @@ -446,12 +478,14 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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) @@ -460,7 +494,8 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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) @@ -469,7 +504,8 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or 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); } /** @@ -506,13 +542,14 @@ static void _DoCommandReturnSetOrderFlags(class AIInstance *instance) 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()) { @@ -521,16 +558,16 @@ static void _DoCommandReturnSetOrderFlags(class AIInstance *instance) 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; @@ -561,7 +598,9 @@ static void _DoCommandReturnSetOrderFlags(class AIInstance *instance) 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) diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index cc5162d575..49c6bbf28c 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -2457,7 +2457,7 @@ static void TileLoop_Track(TileIndex tile) TileIndex n = tile + TileDiffXY(0, -1); TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE); - if (!IsTileType(n, MP_RAILWAY) || + if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) || !IsTileOwner(n, owner) || nrail == TRACK_BIT_UPPER || nrail == TRACK_BIT_LEFT) { @@ -2472,7 +2472,7 @@ static void TileLoop_Track(TileIndex tile) TileIndex n = tile + TileDiffXY(0, 1); TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE); - if (!IsTileType(n, MP_RAILWAY) || + if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) || !IsTileOwner(n, owner) || nrail == TRACK_BIT_LOWER || nrail == TRACK_BIT_RIGHT) { @@ -2488,7 +2488,7 @@ static void TileLoop_Track(TileIndex tile) TileIndex n = tile + TileDiffXY(-1, 0); TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE); - if (!IsTileType(n, MP_RAILWAY) || + if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) || !IsTileOwner(n, owner) || nrail == TRACK_BIT_UPPER || nrail == TRACK_BIT_RIGHT) { @@ -2503,7 +2503,7 @@ static void TileLoop_Track(TileIndex tile) TileIndex n = tile + TileDiffXY(1, 0); TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE); - if (!IsTileType(n, MP_RAILWAY) || + if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) || !IsTileOwner(n, owner) || nrail == TRACK_BIT_LOWER || nrail == TRACK_BIT_LEFT) {