ship_cmd.c
changeset 193 0a7025304867
parent 164 0cbdf3c9bde1
child 297 6c4ab6ff031f
equal deleted inserted replaced
192:614bba52258d 193:0a7025304867
    91 	if (SERVICE_INTERVAL)
    91 	if (SERVICE_INTERVAL)
    92 		return;
    92 		return;
    93 
    93 
    94 	if (v->vehstatus & VS_STOPPED)
    94 	if (v->vehstatus & VS_STOPPED)
    95 		return;
    95 		return;
    96 	
    96 
    97 	if ((v->next_order & (OT_MASK | OF_FULL_LOAD)) == (OT_GOTO_DEPOT | OF_FULL_LOAD))
    97 	if ((v->next_order & (OT_MASK | OF_FULL_LOAD)) == (OT_GOTO_DEPOT | OF_FULL_LOAD))
    98 		return;
    98 		return;
    99 
    99 
   100 	if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr))
   100 	if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr))
   101 		return;
   101 		return;
   111 	}
   111 	}
   112 
   112 
   113 	v->next_order = OT_GOTO_DEPOT | OF_NON_STOP;
   113 	v->next_order = OT_GOTO_DEPOT | OF_NON_STOP;
   114 	v->next_order_param = (byte)i;
   114 	v->next_order_param = (byte)i;
   115 	v->dest_tile = (&_depots[i])->xy;
   115 	v->dest_tile = (&_depots[i])->xy;
   116 	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);		
   116 	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);
   117 }
   117 }
   118 
   118 
   119 void OnNewDay_Ship(Vehicle *v)
   119 void OnNewDay_Ship(Vehicle *v)
   120 {
   120 {
   121 	int32 cost;
   121 	int32 cost;
   126 	CheckVehicleBreakdown(v);
   126 	CheckVehicleBreakdown(v);
   127 	AgeVehicle(v);
   127 	AgeVehicle(v);
   128 	CheckIfShipNeedsService(v);
   128 	CheckIfShipNeedsService(v);
   129 
   129 
   130 	CheckOrders(v);
   130 	CheckOrders(v);
   131 	
   131 
   132 	if (v->vehstatus & VS_STOPPED)
   132 	if (v->vehstatus & VS_STOPPED)
   133 		return;
   133 		return;
   134 
   134 
   135 	
   135 
   136 
   136 
   137 	cost = ship_vehicle_info(v->engine_type).running_cost * _price.ship_running / 364;
   137 	cost = ship_vehicle_info(v->engine_type).running_cost * _price.ship_running / 364;
   138 	v->profit_this_year -= cost >> 8;
   138 	v->profit_this_year -= cost >> 8;
   139 
   139 
   140 	SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
   140 	SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
   150 		v->breakdown_ctr = 1;
   150 		v->breakdown_ctr = 1;
   151 		v->cur_speed = 0;
   151 		v->cur_speed = 0;
   152 
   152 
   153 		if (v->breakdowns_since_last_service != 255)
   153 		if (v->breakdowns_since_last_service != 255)
   154 			v->breakdowns_since_last_service++;
   154 			v->breakdowns_since_last_service++;
   155 		
   155 
   156 		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
   156 		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
   157 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
   157 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
   158 		
   158 
   159 		SndPlayVehicleFx((_opt.landscape != LT_CANDY) ? 0xE : 0x3A, v);
   159 		SndPlayVehicleFx((_opt.landscape != LT_CANDY) ? 0xE : 0x3A, v);
   160 
   160 
   161 		if (!(v->vehstatus & VS_HIDDEN)) {
   161 		if (!(v->vehstatus & VS_HIDDEN)) {
   162 			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
   162 			Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
   163 			if (u)
   163 			if (u)
   229 	v->next_order_param = (byte)(order >> 8);
   229 	v->next_order_param = (byte)(order >> 8);
   230 
   230 
   231 	if ((order & OT_MASK) == OT_GOTO_STATION) {
   231 	if ((order & OT_MASK) == OT_GOTO_STATION) {
   232 		if ( (byte)(order >> 8) == v->last_station_visited)
   232 		if ( (byte)(order >> 8) == v->last_station_visited)
   233 			v->last_station_visited = 0xFF;
   233 			v->last_station_visited = 0xFF;
   234 		
   234 
   235 		st = DEREF_STATION(order >> 8);
   235 		st = DEREF_STATION(order >> 8);
   236 		if (st->dock_tile != 0) {
   236 		if (st->dock_tile != 0) {
   237 			v->dest_tile = TILE_ADD(st->dock_tile, _dock_offs[_map5[st->dock_tile]-0x4B]);
   237 			v->dest_tile = TILE_ADD(st->dock_tile, _dock_offs[_map5[st->dock_tile]-0x4B]);
   238 		}
   238 		}
   239 	} else if ((order & OT_MASK) == OT_GOTO_DEPOT) {
   239 	} else if ((order & OT_MASK) == OT_GOTO_DEPOT) {
   246 
   246 
   247 static void HandleShipLoading(Vehicle *v)
   247 static void HandleShipLoading(Vehicle *v)
   248 {
   248 {
   249 	if (v->next_order == OT_NOTHING)
   249 	if (v->next_order == OT_NOTHING)
   250 		return;
   250 		return;
   251 	
   251 
   252 	if (v->next_order != OT_DUMMY) {
   252 	if (v->next_order != OT_DUMMY) {
   253 		if ((v->next_order&OT_MASK) != OT_LOADING)
   253 		if ((v->next_order&OT_MASK) != OT_LOADING)
   254 			return;
   254 			return;
   255 
   255 
   256 		if (--v->load_unload_time_rem)
   256 		if (--v->load_unload_time_rem)
   263 				MarkShipDirty(v);
   263 				MarkShipDirty(v);
   264 			}
   264 			}
   265 			return;
   265 			return;
   266 		}
   266 		}
   267 		PlayShipSound(v);
   267 		PlayShipSound(v);
   268 		
   268 
   269 		{
   269 		{
   270 			byte b = v->next_order;
   270 			byte b = v->next_order;
   271 			v->next_order = OT_LEAVESTATION;
   271 			v->next_order = OT_LEAVESTATION;
   272 			if (!(b & OF_NON_STOP))
   272 			if (!(b & OF_NON_STOP))
   273 				return;
   273 				return;
   350 
   350 
   351 	spd = min(v->cur_speed + 1, v->max_speed);
   351 	spd = min(v->cur_speed + 1, v->max_speed);
   352 
   352 
   353 	//updates statusbar only if speed have changed to save CPU time
   353 	//updates statusbar only if speed have changed to save CPU time
   354 	if (spd != v->cur_speed) {
   354 	if (spd != v->cur_speed) {
   355 		v->cur_speed = spd;	
   355 		v->cur_speed = spd;
   356 		if (_patches.vehicle_speed)
   356 		if (_patches.vehicle_speed)
   357 			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);
   357 			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);
   358 	}
   358 	}
   359 
   359 
   360 	// Decrease somewhat when turning
   360 	// Decrease somewhat when turning
   382 
   382 
   383 	v->u.ship.state = 0x80;
   383 	v->u.ship.state = 0x80;
   384 	v->vehstatus |= VS_HIDDEN;
   384 	v->vehstatus |= VS_HIDDEN;
   385 	v->cur_speed = 0;
   385 	v->cur_speed = 0;
   386 	RecalcShipStuff(v);
   386 	RecalcShipStuff(v);
   387 	
   387 
   388 	v->date_of_last_service = _date;
   388 	v->date_of_last_service = _date;
   389 	v->breakdowns_since_last_service = 0;
   389 	v->breakdowns_since_last_service = 0;
   390 	v->reliability = _engines[v->engine_type].reliability;
   390 	v->reliability = _engines[v->engine_type].reliability;
   391 	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
   391 	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
   392 
   392 
   393 	MaybeRenewVehicle(v, EstimateShipCost(v->engine_type));
   393 	MaybeRenewVehicle(v, EstimateShipCost(v->engine_type));
   394 
   394 
   395 	if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT) {
   395 	if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT) {
   396 		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
   396 		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
   397 	
   397 
   398 		t = v->next_order;
   398 		t = v->next_order;
   399 		v->next_order = OT_DUMMY;
   399 		v->next_order = OT_DUMMY;
   400 
   400 
   401 		if (t&OF_UNLOAD) { v->cur_order_index++; }
   401 		if (t&OF_UNLOAD) { v->cur_order_index++; }
   402 
   402 
   442 static bool ShipTrackFollower(uint tile, PathFindShip *pfs, int track, uint length, byte *state)
   442 static bool ShipTrackFollower(uint tile, PathFindShip *pfs, int track, uint length, byte *state)
   443 {
   443 {
   444 	// Found dest?
   444 	// Found dest?
   445 	if (tile == pfs->dest_coords) {
   445 	if (tile == pfs->dest_coords) {
   446 		pfs->best_bird_dist = 0;
   446 		pfs->best_bird_dist = 0;
   447 		
   447 
   448 //		if (length < pfs->best_length)
   448 //		if (length < pfs->best_length)
   449 //			dbg_store_path();
   449 //			dbg_store_path();
   450 
   450 
   451 		pfs->best_length = minu(pfs->best_length, length);
   451 		pfs->best_length = minu(pfs->best_length, length);
   452 		return true;
   452 		return true;
   454 
   454 
   455 	// Skip this tile in the calculation
   455 	// Skip this tile in the calculation
   456 	if (tile != pfs->skiptile) {
   456 	if (tile != pfs->skiptile) {
   457 		pfs->best_bird_dist = minu(pfs->best_bird_dist, GetTileDist1Db(pfs->dest_coords, tile));
   457 		pfs->best_bird_dist = minu(pfs->best_bird_dist, GetTileDist1Db(pfs->dest_coords, tile));
   458 	}
   458 	}
   459 	
   459 
   460 	return false;
   460 	return false;
   461 }
   461 }
   462 
   462 
   463 static const byte _ship_search_directions[6][4] = {
   463 static const byte _ship_search_directions[6][4] = {
   464 	{ 0, 9, 2, 9 },
   464 	{ 0, 9, 2, 9 },
   486 	best_track = -1;
   486 	best_track = -1;
   487 
   487 
   488 	do {
   488 	do {
   489 		i = FIND_FIRST_BIT(bits);
   489 		i = FIND_FIRST_BIT(bits);
   490 		bits = KILL_FIRST_BIT(bits);
   490 		bits = KILL_FIRST_BIT(bits);
   491 		
   491 
   492 		pfs.best_bird_dist = (uint)-1;
   492 		pfs.best_bird_dist = (uint)-1;
   493 		pfs.best_length = (uint)-1;
   493 		pfs.best_length = (uint)-1;
   494 
   494 
   495 		FollowTrack(tile, 0x3800 | TRANSPORT_WATER, _ship_search_directions[i][dir], (TPFEnumProc*)ShipTrackFollower, NULL, &pfs);
   495 		FollowTrack(tile, 0x3800 | TRANSPORT_WATER, _ship_search_directions[i][dir], (TPFEnumProc*)ShipTrackFollower, NULL, &pfs);
   496 		
   496 
   497 		if (best_track >= 0) {
   497 		if (best_track >= 0) {
   498 			if (pfs.best_bird_dist != 0) {
   498 			if (pfs.best_bird_dist != 0) {
   499 				/* neither reached the destination, pick the one with the smallest bird dist */
   499 				/* neither reached the destination, pick the one with the smallest bird dist */
   500 				if (pfs.best_bird_dist > best_bird_dist) goto bad;
   500 				if (pfs.best_bird_dist > best_bird_dist) goto bad;
   501 				if (pfs.best_bird_dist < best_bird_dist) goto good;
   501 				if (pfs.best_bird_dist < best_bird_dist) goto good;
   502 			} else {
   502 			} else {
   503 				if (pfs.best_length > best_length) goto bad;
   503 				if (pfs.best_length > best_length) goto bad;
   504 				if (pfs.best_length < best_length) goto good;
   504 				if (pfs.best_length < best_length) goto good;
   505 			}
   505 			}
   506 			
   506 
   507 			/* if we reach this position, there's two paths of equal value so far. 
   507 			/* if we reach this position, there's two paths of equal value so far.
   508 			 * pick one randomly. */
   508 			 * pick one randomly. */
   509 			r = (byte)Random();
   509 			r = (byte)Random();
   510 			if (_pick_shiptrack_table[i] == ship_dir) r += 80;
   510 			if (_pick_shiptrack_table[i] == ship_dir) r += 80;
   511 			if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80;
   511 			if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80;
   512 			if (r <= 127) goto bad;
   512 			if (r <= 127) goto bad;
   552 	2, 3, 4,
   552 	2, 3, 4,
   553 };
   553 };
   554 
   554 
   555 static int ShipGetNewDirectionFromTiles(uint new_tile, uint old_tile)
   555 static int ShipGetNewDirectionFromTiles(uint new_tile, uint old_tile)
   556 {
   556 {
   557 	uint offs = (GET_TILE_Y(new_tile) - GET_TILE_Y(old_tile) + 1) * 4 + 
   557 	uint offs = (GET_TILE_Y(new_tile) - GET_TILE_Y(old_tile) + 1) * 4 +
   558 							GET_TILE_X(new_tile) - GET_TILE_X(old_tile) + 1;
   558 							GET_TILE_X(new_tile) - GET_TILE_X(old_tile) + 1;
   559 	assert(offs < 11 && offs != 3 && offs != 7);
   559 	assert(offs < 11 && offs != 3 && offs != 7);
   560 	return _new_vehicle_direction_table[offs];
   560 	return _new_vehicle_direction_table[offs];
   561 }
   561 }
   562 
   562 
   705 		track = ChooseShipTrack(v, gp.new_tile, dir, tracks);
   705 		track = ChooseShipTrack(v, gp.new_tile, dir, tracks);
   706 		if (track < 0)
   706 		if (track < 0)
   707 			goto reverse_direction;
   707 			goto reverse_direction;
   708 
   708 
   709 		b = _ship_subcoord[dir][track];
   709 		b = _ship_subcoord[dir][track];
   710 	
   710 
   711 		gp.x = (gp.x&~0xF) | b[0];
   711 		gp.x = (gp.x&~0xF) | b[0];
   712 		gp.y = (gp.y&~0xF) | b[1];
   712 		gp.y = (gp.y&~0xF) | b[1];
   713 
   713 
   714 		/* Call the landscape function and tell it that the vehicle entered the tile */
   714 		/* Call the landscape function and tell it that the vehicle entered the tile */
   715 		r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
   715 		r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
   792 	int32 value;
   792 	int32 value;
   793 	Vehicle *v;
   793 	Vehicle *v;
   794 	uint unit_num;
   794 	uint unit_num;
   795 	uint tile = TILE_FROM_XY(x,y);
   795 	uint tile = TILE_FROM_XY(x,y);
   796 	Engine *e;
   796 	Engine *e;
   797 	
   797 
   798 	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
   798 	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
   799 
   799 
   800 	value = EstimateShipCost(p1);
   800 	value = EstimateShipCost(p1);
   801 	if (flags & DC_QUERY_COST)
   801 	if (flags & DC_QUERY_COST)
   802 		return value;
   802 		return value;
   803 
   803 
   804 	v = AllocateVehicle();
   804 	v = AllocateVehicle();
   805 	if (v == NULL || _ptr_to_next_order >= endof(_order_array) || 
   805 	if (v == NULL || _ptr_to_next_order >= endof(_order_array) ||
   806 			(unit_num = GetFreeUnitNumber(VEH_Ship)) > _patches.max_ships)
   806 			(unit_num = GetFreeUnitNumber(VEH_Ship)) > _patches.max_ships)
   807 		return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
   807 		return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
   808 	
   808 
   809 	if (flags & DC_EXEC) {
   809 	if (flags & DC_EXEC) {
   810 		v->unitnumber = unit_num;
   810 		v->unitnumber = unit_num;
   811 
   811 
   812 		v->owner = _current_player;
   812 		v->owner = _current_player;
   813 		v->tile = tile;
   813 		v->tile = tile;
   821 		v->sprite_width = 6;
   821 		v->sprite_width = 6;
   822 		v->sprite_height = 6;
   822 		v->sprite_height = 6;
   823 		v->x_offs = -3;
   823 		v->x_offs = -3;
   824 		v->y_offs = -3;
   824 		v->y_offs = -3;
   825 		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
   825 		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
   826 		
   826 
   827 		v->spritenum = ship_vehicle_info(p1).image_index;
   827 		v->spritenum = ship_vehicle_info(p1).image_index;
   828 		v->cargo_type = ship_vehicle_info(p1).cargo_type;
   828 		v->cargo_type = ship_vehicle_info(p1).cargo_type;
   829 		v->cargo_cap = ship_vehicle_info(p1).capacity;
   829 		v->cargo_cap = ship_vehicle_info(p1).capacity;
   830 		v->value = value;
   830 		v->value = value;
   831 		
   831 
   832 		v->last_station_visited = 255;
   832 		v->last_station_visited = 255;
   833 		v->max_speed = ship_vehicle_info(p1).max_speed;
   833 		v->max_speed = ship_vehicle_info(p1).max_speed;
   834 		v->engine_type = (byte)p1;
   834 		v->engine_type = (byte)p1;
   835 
   835 
   836 		e = &_engines[p1];
   836 		e = &_engines[p1];
   854 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
   854 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
   855 		_vehicle_sort_dirty[VEHSHIP] = true; // build a ship
   855 		_vehicle_sort_dirty[VEHSHIP] = true; // build a ship
   856 		InvalidateWindow(WC_SHIPS_LIST, v->owner);
   856 		InvalidateWindow(WC_SHIPS_LIST, v->owner);
   857 		InvalidateWindow(WC_COMPANY, v->owner);
   857 		InvalidateWindow(WC_COMPANY, v->owner);
   858 	}
   858 	}
   859 	
   859 
   860 	return value;
   860 	return value;
   861 }
   861 }
   862 
   862 
   863 int32 CmdSellShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
   863 int32 CmdSellShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
   864 {
   864 {
   865 	Vehicle *v;
   865 	Vehicle *v;
   866 
   866 
   867 	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
   867 	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
   868 	
   868 
   869 	v = &_vehicles[p1];
   869 	v = &_vehicles[p1];
   870 
   870 
   871 	if (!CheckOwnership(v->owner))
   871 	if (!CheckOwnership(v->owner))
   872 		return CMD_ERROR;
   872 		return CMD_ERROR;
   873 
   873 
   874 	if (!IsShipDepotTile(v->tile) || v->u.road.state != 0x80 || !(v->vehstatus&VS_STOPPED))
   874 	if (!IsShipDepotTile(v->tile) || v->u.road.state != 0x80 || !(v->vehstatus&VS_STOPPED))
   875 		return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
   875 		return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
   876 	
   876 
   877 	if (flags & DC_EXEC) {
   877 	if (flags & DC_EXEC) {
   878 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
   878 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
   879 		_vehicle_sort_dirty[VEHSHIP] = true; // sell a ship
   879 		_vehicle_sort_dirty[VEHSHIP] = true; // sell a ship
   880 		InvalidateWindow(WC_SHIPS_LIST, v->owner);
   880 		InvalidateWindow(WC_SHIPS_LIST, v->owner);
   881 		InvalidateWindow(WC_COMPANY, v->owner);
   881 		InvalidateWindow(WC_COMPANY, v->owner);
   882 		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
   882 		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
   883 		DeleteVehicle(v);
   883 		DeleteVehicle(v);
   884 	}
   884 	}
   885 	
   885 
   886 	return -(int32)v->value;
   886 	return -(int32)v->value;
   887 }
   887 }
   888 
   888 
   889 // p1 = vehicle
   889 // p1 = vehicle
   890 int32 CmdStartStopShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
   890 int32 CmdStartStopShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
   917 
   917 
   918 	if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT) {
   918 	if ((v->next_order&OT_MASK) == OT_GOTO_DEPOT) {
   919 		if (flags & DC_EXEC) {
   919 		if (flags & DC_EXEC) {
   920 			if (v->next_order&OF_UNLOAD) {v->cur_order_index++;}
   920 			if (v->next_order&OF_UNLOAD) {v->cur_order_index++;}
   921 			v->next_order = OT_DUMMY;
   921 			v->next_order = OT_DUMMY;
   922 			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);			
   922 			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, 4);
   923 		}
   923 		}
   924 	} else {
   924 	} else {
   925 		depot = FindClosestShipDepot(v);
   925 		depot = FindClosestShipDepot(v);
   926 		if (depot < 0)
   926 		if (depot < 0)
   927 			return_cmd_error(STR_981A_UNABLE_TO_FIND_LOCAL_DEPOT);
   927 			return_cmd_error(STR_981A_UNABLE_TO_FIND_LOCAL_DEPOT);
   961 {
   961 {
   962 	Vehicle *v;
   962 	Vehicle *v;
   963 	int32 cost;
   963 	int32 cost;
   964 
   964 
   965 	SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
   965 	SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
   966 	
   966 
   967 	v = &_vehicles[p1];
   967 	v = &_vehicles[p1];
   968 	if (!CheckOwnership(v->owner))
   968 	if (!CheckOwnership(v->owner))
   969 		return CMD_ERROR;
   969 		return CMD_ERROR;
   970 
   970 
   971 	if (!IsShipDepotTile(v->tile) ||
   971 	if (!IsShipDepotTile(v->tile) ||