/// <summary> /// /// </summary> /// <param name="state"></param> /// <returns></returns> public object onInside(CarState.Inside state) { TrainCar head = owner.head; RailRoad rr = RailRoad.get(state.location); Direction go = rr.Guide(); // angle to go Location newLoc = state.location + go; newLoc.z += rr.ZDiff(state.direction); if (WorldDefinition.World.IsBorderOfWorld(newLoc)) { // go outside the world return(new CarState.Outside(newLoc, go, OUTSIDE_COUNTER_INITIAL_VALUE)); } else { if (isConnected(newLoc, go)) { // the rail needs to be connected return(new CarState.Inside(newLoc, go)); } else { return(null); } } }
/// <summary> /// Plays a sound effect for this train if necessary. /// </summary> public void playSound(ISoundEffect se) { CarState.Inside ins = head.State.asInside(); if (ins != null) { se.play(ins.location); // play the sound } }
/// <summary> /// /// </summary> /// <param name="tr"></param> /// <param name="callCount"></param> /// <returns></returns> public override TimeLength getStopTimeSpan(Train tr, int callCount) { // calculate the position where the train should stop. int pos; CarState.Inside ins = tr.head.State.asInside(); if (owner.direction == ins.direction) { pos = (owner.length + tr.length) / 2 - 1; } else { Debug.Assert(owner.direction == ins.direction.opposite); pos = (owner.length - tr.length) / 2; } if (pos < 0 || pos >= owner.length) { return(TimeLength.ZERO); // longer than the platform } if (pos != index) { return(TimeLength.ZERO); // not at the stop position } // the train is positioned at the right place. if (owner.hostStation == null) { return(TimeLength.ZERO); // platform is not connected. can't make a stop } // ask the controller to see if it wants to stop. TimeLength ts = tr.controller.getStopTimeSpan(tr, owner.hostStation, callCount); if (callCount == 0 && ts.isPositive) { // if the train stops, unload passengers owner.hostStation.unloadPassengers(tr); } if (callCount != 0 && !ts.isPositive) { // if the train departs, load passengers owner.hostStation.loadPassengers(tr); // ring the bell, here we go! tr.playSound(owner.bellSound.Sound); } return(ts); }
/// <summary> /// /// </summary> /// <param name="state"></param> /// <returns></returns> public object onOutsie(CarState.Outside state) { CarState.Inside s = calcReturnPoint(state); if (s == null) { // all the usable RRs are completely removed. // that means this train is fully outside the world. // so it's OK to remain static. return(state); } return(new CarState.Outside( s.location - s.direction, s.direction.opposite, OUTSIDE_COUNTER_INITIAL_VALUE - state.timeLeft)); }
/// <summary> /// /// </summary> /// <param name="view"></param> /// <param name="dc"></param> public void DrawAfter(QuarterViewDrawer view, DrawContext dc) { Train tr = this.selectedTrain; if (tr == null || !tr.head.State.isInside) { return; } // draw an arrow that indicates the direction of the train CarState.Inside ci = tr.head.State.asInside(); Point pt = view.fromXYZToClient(ci.location); pt.Y -= 12; ci.direction.drawArrow(dc.Surface, pt); }
/// <summary> /// /// </summary> /// <param name="dc"></param> /// <param name="pt"></param> public override void Draw(DrawContext dc, Point pt) { Surface display = dc.Surface; pt.Y -= 9; // offset CarState.Inside s = State.asInside(); Debug.Assert(s != null); RailRoad rr = s.voxel.railRoad; if (rr is SlopeRailRoad) { // slope rail SlopeRailRoad srr = (SlopeRailRoad)rr; switch (srr.level) {// apply slope height case 0: break; case 1: pt.Y -= 4; break; case 2: pt.Y += 8; break; case 3: pt.Y += 4; break; } if (!parent.isReversed) { type.DrawSlope(display, pt, s.direction, s.direction == srr.climbDir); } else { type.DrawSlope(display, pt, s.direction.opposite, s.direction != srr.climbDir); } } else { // level rail road int d1 = s.direction.index; int d2 = s.voxel.railRoad.Guide().index; int angle; if (d1 == d2) { angle = d1 * 2; } else { int diff = (d2 - d1) & 7; if (diff == 7) { diff = -1; } int dd = (d2 * 2 + diff * 3) & 15; // operation is on modulo 16. if (2 < dd && dd < 10) { pt.X += 3; } else { pt.X -= 3; } if (6 < dd && dd <= 14) { pt.Y += 2; } else { pt.Y -= 2; } angle = (d1 * 2 + diff) & 15; } if (parent.isReversed) { angle ^= 8; } type.Draw(display, pt, angle); } }
public object onInside(CarState.Inside state) { return(state.voxel.isOccupied); }
/// <summary> /// /// </summary> /// <param name="state"></param> /// <returns></returns> public object onInside(CarState.Inside state) { Direction d = state.voxel.railRoad.Guide().opposite; return(new CarState.Inside(state.location, d)); }
/// <summary> /// Clock event handler. /// </summary> public void clockHandler() { Debug.Assert(isPlaced); // we should have unregistered the handler when the train was removed. CarState.Inside ins = head.State.asInside(); if (ins != null) { // this car might need to stop TimeLength time = ins.voxel.railRoad.getStopTimeSpan(this, stopCallCount); if (time.totalMinutes > 0) { stopCallCount++; // a car needs to stop here registerTimer(time); // resume after the specified time // TODO: see where this train is being stopped. do something if necessary State = TrainStates.StoppingAtStation; return; } if (time.totalMinutes < 0) { reverse(); // turn around } } // this car can now move stopCallCount = 0; TrainStates s = TrainStates.Moving; // determine the next head car state CarState next = calcNextTrainCarState[head.State]; if (next != null) { // if it can move forward if (!isBlocked[next]) { move(next); } else { // otherwise we can't move. emergency stop. s = TrainStates.EmergencyStopping; } } else { // we can't go forward. turn around reverse(); next = calcNextTrainCarState[head.State]; if (next != null && !isBlocked[next]) { move(next); } else { s = TrainStates.EmergencyStopping; } } State = s; // update the state registerTimer(); }