/** * Enter the road stop * @param rv the vehicle that enters the stop * @return whether the road stop could actually be entered */ bool RoadStop::Enter(RoadVehicle *rv) { if (IsStandardRoadStopTile(this->xy)) { /* For normal (non drive-through) road stops * Check if station is busy or if there are no free bays or whether it is a articulated vehicle. */ if (this->IsEntranceBusy() || !this->HasFreeBay() || rv->HasArticulatedPart()) return false; SetBit(rv->state, RVS_IN_ROAD_STOP); /* Allocate a bay and update the road state */ uint bay_nr = this->AllocateBay(); SB(rv->state, RVS_USING_SECOND_BAY, 1, bay_nr); /* Mark the station entrace as busy */ this->SetEntranceBusy(true); return true; } /* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */ this->GetEntry(DirToDiagDir(rv->direction))->Enter(rv); /* Indicate a drive-through stop */ SetBit(rv->state, RVS_IN_DT_ROAD_STOP); return true; }
/** * Leave the road stop * @param rv the vehicle that leaves the stop */ void RoadStop::Leave(RoadVehicle *rv) { if (IsStandardRoadStopTile(rv->tile)) { /* Vehicle is leaving a road stop tile, mark bay as free */ this->FreeBay(HasBit(rv->state, RVS_USING_SECOND_BAY)); this->SetEntranceBusy(false); } else { /* Otherwise just leave the drive through's entry cache. */ this->GetEntry(DirToDiagDir(rv->direction))->Leave(rv); } }
Trackdir Ship::GetVehicleTrackdir() const { if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR; if (this->IsInDepot()) { /* We'll assume the ship is facing outwards */ return DiagDirToDiagTrackdir(GetShipDepotDirection(this->tile)); } if (this->state == TRACK_BIT_WORMHOLE) { /* ship on aqueduct, so just use his direction and assume a diagonal track */ return DiagDirToDiagTrackdir(DirToDiagDir(this->direction)); } return TrackDirectionToTrackdir(FindFirstTrack(this->state), this->direction); }
/** * Add road vehicles to the station's list if needed. * @param v the found vehicle * @param data the extra data used to make our decision * @return always NULL */ Vehicle *FindVehiclesInRoadStop(Vehicle *v, void *data) { RoadStopEntryRebuilderHelper *rserh = (RoadStopEntryRebuilderHelper*)data; /* Not a RV or not in the right direction or crashed :( */ if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return NULL; RoadVehicle *rv = RoadVehicle::From(v); /* Don't add ones not in a road stop */ if (rv->state < RVSB_IN_ROAD_STOP) return NULL; /* Do not add duplicates! */ for (RVList::iterator it = rserh->vehicles.begin(); it != rserh->vehicles.end(); it++) { if (rv == *it) return NULL; } rserh->vehicles.push_back(rv); return NULL; }
/** * Updates vehicle's Z position. * Inclination can't change in the middle of a tile. * The faster code is used for trains and road vehicles unless they are * reversing on a sloped tile. */ FORCEINLINE void UpdateZPosition() { #if 0 /* The following code does this: */ if (HasBit(this->gv_flags, GVF_GOINGUP_BIT)) { switch (this->direction) { case DIR_NE: this->z_pos += (this->x_pos & 1); break; case DIR_SW: this->z_pos += (this->x_pos & 1) ^ 1; break; case DIR_NW: this->z_pos += (this->y_pos & 1); break; case DIR_SE: this->z_pos += (this->y_pos & 1) ^ 1; break; default: break; } } else if (HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) { switch (this->direction) { case DIR_NE: this->z_pos -= (this->x_pos & 1); break; case DIR_SW: this->z_pos -= (this->x_pos & 1) ^ 1; break; case DIR_NW: this->z_pos -= (this->y_pos & 1); break; case DIR_SE: this->z_pos -= (this->y_pos & 1) ^ 1; break; default: break; } } /* But gcc 4.4.5 isn't able to nicely optimise it, and the resulting * code is full of conditional jumps. */ #endif /* Vehicle's Z position can change only if it has GVF_GOINGUP_BIT or GVF_GOINGDOWN_BIT set. * Furthermore, if this function is called once every time the vehicle's position changes, * we know the Z position changes by +/-1 at certain moments - when x_pos, y_pos is odd/even, * depending on orientation of the slope and vehicle's direction */ if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) { if (T::From(this)->HasToUseGetSlopeZ()) { /* In some cases, we have to use GetSlopeZ() */ this->z_pos = GetSlopeZ(this->x_pos, this->y_pos); return; } /* DirToDiagDir() is a simple right shift */ DiagDirection dir = DirToDiagDir(this->direction); /* Read variables, so the compiler knows the access doesn't trap */ int8 x_pos = this->x_pos; int8 y_pos = this->y_pos; /* DiagDirToAxis() is a simple mask */ int8 d = DiagDirToAxis(dir) == AXIS_X ? x_pos : y_pos; /* We need only the least significant bit */ d &= 1; /* Conditional "^ 1". Optimised to "(dir - 1) <= 1". */ d ^= (int8)(dir == DIAGDIR_SW || dir == DIAGDIR_SE); /* Subtraction instead of addition because we are testing for GVF_GOINGUP_BIT. * GVF_GOINGUP_BIT is used because it's bit 0, so simple AND can be used, * without any shift */ this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d; } assert(this->z_pos == GetSlopeZ(this->x_pos, this->y_pos)); }
static void ShipController(Ship *v) { uint32 r; const byte *b; Direction dir; Track track; TrackBits tracks; v->tick_counter++; v->current_order_time++; if (v->breakdown_ctr != 0) { if (v->breakdown_ctr <= 2) { HandleBrokenShip(v); return; } if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--; } if (v->vehstatus & VS_STOPPED) return; ProcessOrders(v); v->HandleLoading(); if (v->current_order.IsType(OT_LOADING)) return; CheckShipLeaveDepot(v); if (!ShipAccelerate(v)) return; GetNewVehiclePosResult gp = GetNewVehiclePos(v); if (v->state != TRACK_BIT_WORMHOLE) { /* Not on a bridge */ if (gp.old_tile == gp.new_tile) { /* Staying in tile */ if (v->IsInDepot()) { gp.x = v->x_pos; gp.y = v->y_pos; } else { /* Not inside depot */ r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); if (HasBit(r, VETS_CANNOT_ENTER)) goto reverse_direction; /* A leave station order only needs one tick to get processed, so we can * always skip ahead. */ if (v->current_order.IsType(OT_LEAVESTATION)) { v->current_order.Free(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); } else if (v->dest_tile != 0) { /* We have a target, let's see if we reached it... */ if (v->current_order.IsType(OT_GOTO_WAYPOINT) && DistanceManhattan(v->dest_tile, gp.new_tile) <= 3) { /* We got within 3 tiles of our target buoy, so let's skip to our * next order */ UpdateVehicleTimetable(v, true); v->IncrementOrderIndex(); v->current_order.MakeDummy(); } else { /* Non-buoy orders really need to reach the tile */ if (v->dest_tile == gp.new_tile) { if (v->current_order.IsType(OT_GOTO_DEPOT)) { if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) { VehicleEnterDepot(v); return; } } else if (v->current_order.IsType(OT_GOTO_STATION)) { v->last_station_visited = v->current_order.GetDestination(); /* Process station in the orderlist. */ Station *st = Station::Get(v->current_order.GetDestination()); if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations ShipArrivesAt(v, st); v->BeginLoading(); } else { // leave stations without docks right aways v->current_order.MakeLeaveStation(); v->IncrementOrderIndex(); } } } } } } } else { DiagDirection diagdir; /* New tile */ if (TileX(gp.new_tile) >= MapMaxX() || TileY(gp.new_tile) >= MapMaxY()) { goto reverse_direction; } dir = ShipGetNewDirectionFromTiles(gp.new_tile, gp.old_tile); assert(dir == DIR_NE || dir == DIR_SE || dir == DIR_SW || dir == DIR_NW); diagdir = DirToDiagDir(dir); tracks = GetAvailShipTracks(gp.new_tile, diagdir); if (tracks == TRACK_BIT_NONE) goto reverse_direction; /* Choose a direction, and continue if we find one */ track = ChooseShipTrack(v, gp.new_tile, diagdir, tracks); if (track == INVALID_TRACK) goto reverse_direction; b = _ship_subcoord[diagdir][track]; gp.x = (gp.x & ~0xF) | b[0]; gp.y = (gp.y & ~0xF) | b[1]; /* Call the landscape function and tell it that the vehicle entered the tile */ r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); if (HasBit(r, VETS_CANNOT_ENTER)) goto reverse_direction; if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { v->tile = gp.new_tile; v->state = TrackToTrackBits(track); } v->direction = (Direction)b[2]; } } else { /* On a bridge */ if (!IsTileType(gp.new_tile, MP_TUNNELBRIDGE) || !HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) { v->x_pos = gp.x; v->y_pos = gp.y; VehicleMove(v, !(v->vehstatus & VS_HIDDEN)); return; } } /* update image of ship, as well as delta XY */ dir = ShipGetNewDirection(v, gp.x, gp.y); v->x_pos = gp.x; v->y_pos = gp.y; v->z_pos = GetSlopeZ(gp.x, gp.y); getout: v->UpdateViewport(true, true); return; reverse_direction: dir = ReverseDir(v->direction); v->direction = dir; goto getout; }