order_cmd.c
changeset 0 29654efe3188
child 19 6080d2b6a959
equal deleted inserted replaced
-1:000000000000 0:29654efe3188
       
     1 #include "stdafx.h"
       
     2 #include "ttd.h"
       
     3 #include "vehicle.h"
       
     4 #include "command.h"
       
     5 #include "station.h"
       
     6 #include "player.h"
       
     7 
       
     8 /* p1 & 0xFFFF = vehicle
       
     9  * p1 >> 16 = index in order list
       
    10  * p2 = order command to insert
       
    11  */
       
    12 int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
    13 {
       
    14 	Vehicle *v = &_vehicles[p1 & 0xFFFF];
       
    15 	int sel = p1 >> 16;
       
    16 	int t;
       
    17 
       
    18 	if (sel > v->num_orders) return_cmd_error(STR_EMPTY);
       
    19 	if (_ptr_to_next_order == endof(_order_array)) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
       
    20 	if (v->num_orders >= 40) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
       
    21 
       
    22 	// for ships, make sure that the station is not too far away from the previous destination.
       
    23 	if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) &&
       
    24 			sel != 0 && ((t=v->schedule_ptr[sel-1])&OT_MASK) == OT_GOTO_STATION) {
       
    25 		
       
    26 		int dist = GetTileDist(DEREF_STATION(t >> 8)->xy, DEREF_STATION(p2 >> 8)->xy);
       
    27 		if (dist >= 130)
       
    28 			return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
       
    29 	}
       
    30 
       
    31 	if (flags & DC_EXEC) {
       
    32 		uint16 *s1, *s2;
       
    33 		Vehicle *u;
       
    34 
       
    35 		s1 = &v->schedule_ptr[sel];
       
    36 		s2 = _ptr_to_next_order++;
       
    37 		do s2[1] = s2[0]; while (--s2 >= s1);
       
    38 		s1[0] = (uint16)p2;
       
    39 
       
    40 		s1 = v->schedule_ptr;
       
    41 		
       
    42 		FOR_ALL_VEHICLES(u) {
       
    43 			if (u->type != 0 && u->schedule_ptr != NULL) {
       
    44 				if (s1 < u->schedule_ptr) {
       
    45 					u->schedule_ptr++;
       
    46 				} else if (s1 == u->schedule_ptr) { // handle shared orders
       
    47 					u->num_orders++;
       
    48 
       
    49 					if ((byte)sel <= u->cur_order_index) {
       
    50 						sel++;
       
    51 						if ((byte)sel < u->num_orders)
       
    52 							u->cur_order_index = sel;
       
    53 					}
       
    54 					InvalidateWindow(WC_VEHICLE_VIEW, u->index);
       
    55 					InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
       
    56 				}
       
    57 			}
       
    58 		}
       
    59 	}
       
    60 
       
    61 	return 0;
       
    62 }
       
    63 
       
    64 static int32 DecloneOrder(Vehicle *dst, uint32 flags)
       
    65 {
       
    66 	if (_ptr_to_next_order == endof(_order_array))
       
    67 		return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
       
    68 
       
    69 	if (flags & DC_EXEC) {
       
    70 		DeleteVehicleSchedule(dst);
       
    71 		
       
    72 		dst->num_orders = 0;
       
    73 		*(dst->schedule_ptr = _ptr_to_next_order++) = 0;
       
    74 		
       
    75 		InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
       
    76 	}
       
    77 	return 0;
       
    78 }
       
    79 
       
    80 /* p1 = vehicle
       
    81  * p2 = sel
       
    82  */
       
    83 int32 CmdDeleteOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
    84 {
       
    85 	Vehicle *v = &_vehicles[p1], *u;
       
    86 	uint sel = (uint)p2;
       
    87 
       
    88 	_error_message = STR_EMPTY;
       
    89 	if (sel >= v->num_orders)
       
    90 		return DecloneOrder(v, flags);
       
    91 
       
    92 	if (flags & DC_EXEC) {
       
    93 		uint16 *s1;
       
    94 		
       
    95 		s1 = &v->schedule_ptr[sel];
       
    96 
       
    97 		// copy all orders to get rid of the hole
       
    98 		do s1[0] = s1[1]; while (++s1 != _ptr_to_next_order);
       
    99 		_ptr_to_next_order--;
       
   100 
       
   101 		s1 = v->schedule_ptr;
       
   102 
       
   103 		FOR_ALL_VEHICLES(u) {
       
   104 			if (u->type != 0 && u->schedule_ptr != NULL) {
       
   105 				if (s1 < u->schedule_ptr) {
       
   106 					u->schedule_ptr--;
       
   107 				} else if (s1 == u->schedule_ptr) {// handle shared orders
       
   108 					u->num_orders--;
       
   109 					if ((byte)sel < u->cur_order_index)
       
   110 						u->cur_order_index--;
       
   111 
       
   112 					if ((byte)sel == u->cur_order_index && (u->next_order&(OT_MASK|OF_NON_STOP)) == (OT_LOADING|OF_NON_STOP))
       
   113 						u->next_order = OT_LOADING;
       
   114 
       
   115 					InvalidateWindow(WC_VEHICLE_VIEW, u->index);
       
   116 					InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
       
   117 				}
       
   118 			}
       
   119 		}
       
   120 	}
       
   121 	
       
   122 	return 0;
       
   123 }
       
   124 
       
   125 /* p1 = vehicle */
       
   126 int32 CmdSkipOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
   127 {
       
   128 	if (flags & DC_EXEC) {
       
   129 		Vehicle *v = &_vehicles[p1];
       
   130 
       
   131 		{
       
   132 			byte b = v->cur_order_index + 1;
       
   133 			if (b >= v->num_orders) b = 0;
       
   134 			v->cur_order_index = b;
       
   135 			
       
   136 			if (v->type == VEH_Train)
       
   137 				v->u.rail.days_since_order_progr = 0;
       
   138 		}
       
   139 
       
   140 		if ((v->next_order&(OT_MASK|OF_NON_STOP)) == (OT_LOADING|OF_NON_STOP))
       
   141 			v->next_order = OT_LOADING;
       
   142 
       
   143 		InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
       
   144 	}
       
   145 	return 0;
       
   146 }
       
   147 
       
   148 /* p1 = vehicle
       
   149  * p2&0xFF = sel
       
   150  * p2>>8 = mode
       
   151  */
       
   152 int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
   153 {
       
   154 	Vehicle *v = &_vehicles[p1];
       
   155 	byte sel = (byte)p2;
       
   156 	uint16 *sched;
       
   157 
       
   158 	if (sel >= v->num_orders)
       
   159 		return CMD_ERROR;
       
   160 
       
   161 	sched = &v->schedule_ptr[sel];
       
   162 	if (!((*sched & OT_MASK) == OT_GOTO_STATION || 
       
   163 			((*sched & OT_MASK) == OT_GOTO_DEPOT &&  (p2>>8) != 1)))
       
   164 		return CMD_ERROR;
       
   165 
       
   166 	if (flags & DC_EXEC) {
       
   167 		switch(p2 >> 8) {
       
   168 		case 0: // full load
       
   169 			*sched ^= OF_FULL_LOAD;
       
   170 			if ((*sched & OT_MASK) != OT_GOTO_DEPOT)
       
   171 				*sched &= ~OF_UNLOAD;
       
   172 			break;
       
   173 		case 1: // unload
       
   174 			*sched ^= OF_UNLOAD;
       
   175 			*sched &= ~OF_FULL_LOAD;
       
   176 			break;
       
   177 		case 2: // non stop
       
   178 			*sched ^= OF_NON_STOP;
       
   179 			break;
       
   180 		}
       
   181 		sched = v->schedule_ptr;
       
   182 
       
   183 		FOR_ALL_VEHICLES(v) {
       
   184 			if (v->schedule_ptr == sched)
       
   185 				InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
       
   186 		}
       
   187 		
       
   188 	}
       
   189 	
       
   190 	return 0;
       
   191 }
       
   192 
       
   193 // Clone an order
       
   194 // p1 & 0xFFFF is destination vehicle
       
   195 // p1 >> 16 is source vehicle
       
   196 
       
   197 // p2 is
       
   198 //   0 - clone
       
   199 //   1 - copy
       
   200 //   2 - unclone
       
   201 
       
   202 
       
   203 int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
   204 {
       
   205 	Vehicle *dst = &_vehicles[p1 & 0xFFFF];
       
   206 	
       
   207 	if (!(dst->type && dst->owner == _current_player))
       
   208 		return CMD_ERROR;
       
   209 
       
   210 	switch(p2) {
       
   211 	
       
   212 	// share vehicle orders?
       
   213 	case 0: {
       
   214 		Vehicle *src = &_vehicles[p1 >> 16];
       
   215 
       
   216 		// sanity checks
       
   217 		if (!(src->owner == _current_player && dst->type == src->type && dst != src))
       
   218 			return CMD_ERROR;
       
   219 
       
   220 		if (flags & DC_EXEC) {
       
   221 			DeleteVehicleSchedule(dst);
       
   222 			dst->schedule_ptr = src->schedule_ptr;
       
   223 			dst->num_orders = src->num_orders;
       
   224 
       
   225 			InvalidateWindow(WC_VEHICLE_ORDERS, src->index);
       
   226 			InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
       
   227 		}
       
   228 		break;
       
   229 	}
       
   230 
       
   231 	// copy vehicle orders?
       
   232 	case 1: {
       
   233 		Vehicle *src = &_vehicles[p1 >> 16];
       
   234 		int delta;
       
   235 
       
   236 		// sanity checks
       
   237 		if (!(src->owner == _current_player && dst->type == src->type && dst != src))
       
   238 			return CMD_ERROR;
       
   239 
       
   240 		// make sure there's orders available
       
   241 		delta = IsScheduleShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
       
   242 		if (delta > endof(_order_array) - _ptr_to_next_order)
       
   243 			return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
       
   244 
       
   245 		if (flags & DC_EXEC) {
       
   246 			DeleteVehicleSchedule(dst);
       
   247 			dst->schedule_ptr = _ptr_to_next_order;
       
   248 			dst->num_orders = src->num_orders;
       
   249 			_ptr_to_next_order += src->num_orders + 1;
       
   250 			memcpy(dst->schedule_ptr, src->schedule_ptr, (src->num_orders + 1) * sizeof(uint16));
       
   251 
       
   252 			InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
       
   253 		}
       
   254 		break;
       
   255 	}
       
   256 
       
   257 	// declone vehicle orders?
       
   258 	case 2: return DecloneOrder(dst, flags);
       
   259 	}
       
   260 
       
   261 	return 0;
       
   262 }
       
   263 
       
   264 void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak)
       
   265 {
       
   266 	Vehicle *u = IsScheduleShared(v);
       
   267 	uint16 *sched, ord, *os;
       
   268 
       
   269 	bak->orderindex = v->cur_order_index;
       
   270 	bak->service_interval = v->service_interval;
       
   271 	
       
   272 	if ((v->string_id & 0xF800) != 0x7800) {
       
   273 		bak->name[0] = 0;
       
   274 	} else {
       
   275 		GetName(v->string_id & 0x7FF, bak->name);
       
   276 	}
       
   277 
       
   278 	os = bak->order;
       
   279 	// stored shared orders in this special way?
       
   280 	if (u) {
       
   281 		os[0] = 0xFFFF;
       
   282 		os[1] = u->index;
       
   283 		return;
       
   284 	}
       
   285 	
       
   286 	sched = v->schedule_ptr;
       
   287 	do {
       
   288 		ord = *sched++;
       
   289 		*os++ = ord;
       
   290 	} while (ord != 0);
       
   291 }
       
   292 
       
   293 void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
       
   294 {
       
   295 	uint16 ord, *os;
       
   296 	int ind;
       
   297 
       
   298 	if (bak->name[0]) {
       
   299 		strcpy((char*)_decode_parameters, bak->name);
       
   300 		DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
       
   301 	}
       
   302 
       
   303 	DoCommandP(0, v->index, bak->orderindex|(bak->service_interval<<16) , NULL, CMD_RESTORE_ORDER_INDEX | CMD_ASYNC);
       
   304 	
       
   305 	os = bak->order;
       
   306 	if (os[0] == 0xFFFF) {
       
   307 		DoCommandP(0, v->index | os[1]<<16, 0, NULL, CMD_CLONE_ORDER);
       
   308 		return;
       
   309 	}
       
   310 
       
   311 	ind = 0;
       
   312 	while ((ord = *os++) != 0) {
       
   313 		if (!DoCommandP(0, v->index + (ind << 16), ord, NULL, CMD_INSERT_ORDER | CMD_ASYNC))
       
   314 			break;
       
   315 		ind++;
       
   316 	}
       
   317 }
       
   318 
       
   319 /*	p1 = vehicle
       
   320  *	upper 16 bits p2 = service_interval
       
   321  *	lower 16 bits p2 = cur_order_index
       
   322  */
       
   323 int32 CmdRestoreOrderIndex(int x, int y, uint32 flags, uint32 p1, uint32 p2)
       
   324 {
       
   325 	// nonsense to update the windows, since, train rebought will have its window deleted
       
   326 	if (flags & DC_EXEC) {
       
   327 		Vehicle *v = &_vehicles[p1];
       
   328 		v->service_interval = (uint16)(p2>>16);
       
   329 		v->cur_order_index = (byte)(p2&0xFFFF);
       
   330 	}
       
   331 	return 0;
       
   332 }