T3 Travel actions

Hi all,

I looked over the “connectors” example from Eric Eve and want to modify the “ride” command, so that the player can type:

ride east
and remap it to the standard travel action, but allow the command only when the player is on the bicycle.

In the example the code is:

DefineTAction(Ride)
;

VerbRule(Ride)
    ('ride' | 'mount') singleDobj
    :  RideAction
    verbPhrase = 'ride/riding (what)'
;

DefineTAction(RideDir)
;

VerbRule(RideDir)
    'ride' singleDobj ('to' ('the'|) |) singleDir
    : RideDirAction
    verbPhrase = 'ride/riding (what) (where)'
;

modify Thing
    dobjFor(Ride)
    {
        preCond = [touchObj]
        verify() { illogical(cannotRideMsg); }
    }
    dobjFor(RideDir)
    {
        preCond = [touchObj]
        verify() { illogical(cannotRideMsg); }
    }
    
    cannotRideMsg = '{That dobj/he} {is} not something you can ride. '
;

I didn’t yet find anything in the manuals how to deal with a new travel action.
Has somebody any clue, please?

Best regards
– MI

I wasn’t sure which of Eric’s examples you meant, so I adapted the code for PushTravel actions to accomplish what felt like the desired behavior: riding a bicycle somewhere should result in both the player and the bicycle ending up in the destination, much like pushing an object there would.

DefineTAction(Ride);
DefineTAction(RideDir);
DefineIAction(RideVague);

VerbRule(Ride)
	('ride' | 'mount') singleDobj
	:  RideAction
	verbPhrase = 'ride/riding (what)'
;

VerbRule(RideDir)
	  'ride' singleDobj ('to' ('the'|) |) singleDir
	| 'ride' singleDir  ('on' ('the'|) |) singleDobj
    : RideDirAction
    verbPhrase = ('ride/riding (what) ' + dirMatch.dir.name)
;

VerbRule(RideVague)
	'ride' singleDir
	:  RideVagueAction
	verbPhrase = ('ride/riding ' + dirMatch.dir.name)
;

/*
	 RideTravel is not matched by any grammar rules.
	 RideDir and RideVague remap here to carry out travel.
*/

DefineAction(RideTravel, PushTravelAction)
	performTravel()
	{
		local conn;
		conn = gActor.location.getTravelConnector(getDirection(), gActor);
		nestedAction(TravelVia, conn);
	}
	setDirection(dir) { _dir = dir; }
	getDirection() { return _dir; }
	_dir = nil
;

modify RideDirAction
	execAction()
	{
		// store direction for later use
		RideTravelAction.setDirection(gAction.dirMatch.dir);
		inherited();
	}
;

modify RideVagueAction
	execAction()
	{
		// store direction for later use
		RideTravelAction.setDirection(gAction.dirMatch.dir);

		// player did not specify what to ride; pick something
		local _ride = new Vector(5);
		forEachInstance(Rideable, {obj: gActor.getOutermostRoom() == obj.getOutermostRoom()
										? _ride.append(obj)
										: nil});
		_ride = _ride.sort(true, {a, b: a.rideScore - b.rideScore});

		if (!_ride.length())
			reportFailure(&nothingToRideMsg);
		else
			replaceAction(RideTravel, _ride[1]);
	}

;

modify Thing
	dobjFor(Ride)
	{
		preCond = [touchObj]
		action() { reportFailure(&cannotRideMsg); }
	}

	dobjFor(RideDir)
	{
		preCond = [touchObj]
		action() { reportFailure(&cannotRideMsg); }
	}

;

class Rideable: TravelPushable
	cannotTakeMsg = &cannotTakeRideableMsg
	cannotMoveMsg = &cannotMoveRideableMsg
	cannotPutMsg = &cannotPutRideableMsg

	// show object in the room contents
	isListed = true

	// preference score used when player does not specify what to ride
	rideScore = 100

	dobjFor(Ride)
	{
		action()
		{
			mainReport(&okayRideLocalMsg, self);
		}
	}

	dobjFor(RideDir)
	{
		action()
		{
			replaceAction(RideTravel, gDobj);
		}
	}

	describeMovePushable(traveler, connector)
	{
		if (gActor.isPlayerChar)
			mainReport(&okayRideTravelMsg, self);
	}

	pushTravelerClass = RideTraveler
;

class RideTraveler: PushTraveler
	travelerTravelWithin(actor, dest)
	{
		reportFailure(&cannotRideObjectNestedMsg, obj_);
		exit;
	}
;

class RideTravelBarrier: PushTravelBarrier
    explainTravelBarrier(traveler)
    {
        reportFailure(&cannotRideObjectThatWayMsg, traveler.obj_);
    }
;

modify playerActionMessages
	okayRideLocalMsg(obj)
	{
		return '<.p>{You/he} ride around the area on ' + obj.theNameObj + '. ';
	}

	okayRideTravelMsg(obj)
	{
		return '<.p>{You/he} ride ' + obj.theNameObj + ' into the area. ';
	}

	nothingToRideMsg = 'There is nothing here to ride. '

	cannotRideMsg = '{That dobj/he} {is} not something you can ride. '

	cannotTakeRideableMsg = '{You/he} {can\'t} take {that/him dobj}, but
		{it actor/he} might {be|have been} able to ride it somewhere. '

	cannotMoveRideableMsg = 'It wouldn&rsquo;t {|have} accomplish{|ed}
		anything to move {the dobj/him} around aimlessly, but {it actor/he}
		might {be|have been} able to ride {it dobj/him} in a specific
		direction. '

	cannotPutRideableMsg = '{You/he} {can\'t} put {that/him dobj} anywhere,
		but {it actor/he} might {be|have been} able to ride it somewhere. '

	cannotRideObjectThatWayMsg(obj)
	{
		gMessageParams(obj);
		return '{You/he} {can\'t} go that way riding {the obj/him}. ';
	}

	cannotRideObjectNestedMsg(obj)
	{
		gMessageParams(obj);
		return '{You/he} {can\'t} ride {the obj/him} there. ';
	}
;

tricycle: Rideable 'tricycle' 'TRICYCLE' @storage
	"You had {a dobj/him} just like it as a kid. "
;

This is slightly non-responsive since your specific question isn’t addressed - how to stop the player from traveling in a direction unless they are on the bicycle. To do that you can set a global variable in the performTravel() method of the RideTravel action defined above, then test for that in canActorTravel() method of the room connector in question.