Question about Global Remapping

I have been trying to code a global remapping such that a command of the form KISS X becomes GIVE KISS TO X. This is what I have so far:

kissToGiveKissTo: GlobalRemapping getRemapping(issuingActor, targetActor, action) { if (action.ofKind(KissAction)) { local newAction = GiveToAction.createActionInstance(); newAction.setOriginalAction(action); local dobj = 'kiss'; local iobj = action.dobjMatch; newAction.setObjectMatches(dobj, iobj); return [targetActor, newAction]; } return nil; } ;
I already have a kiss object that allows commands of the form GIVE KISS TO X to work. The string ‘kiss’ obviously needs to be replaced (it is just a placeholder here), but even after reading “Global Command Remapping” in the Technical Manual and “GrammarProd” in the System Manual I don’t know what a viable substitution would be. PreResolvedProd is not an option here, because the kiss object is not directly used in an action (I have instead made it an object in the inventory of an off-stage actor from which other actors inherit). So what do I do? Also, this is the first time I have attempted global remapping, so any other suggested improvements would be appreciated.

Remapping any command to GiveTo seems to cause a nil reference error. I can get this code to work:

[rant][code]
kissToGiveKissTo: GlobalRemapping
getRemapping(issuingActor, targetActor, action)
{
if (action.ofKind(KissAction))
{
local newAction = LockWithAction.createActionInstance();
newAction.setOriginalAction(action);
local dobj = new PreResolvedProd(kiss);
local iobj = action.dobjMatch;
newAction.setObjectMatches(dobj,iobj);

		if (!(iobj.length() == 0))
			return [issuingActor, newAction];
	}
	
	return nil;
}

;
[/code][/rant]

But if I change the newAction instance to GiveToAction, it fails.

Could you use the more straightforward approach of replacing the action during resolution?

[rant][code]
kiss: Thing ‘kiss’ ‘KISS’
"A kiss! "
;

modify Thing
dobjFor(Kiss)
{
check()
{
replaceAction(GiveTo, kiss, self);
}
}
;
[/code][/rant]

Thank you for the help.

I had somehow forgotten about replaceAction(). This works well. It does not seem to matter that the kiss object is in the inventory of the object from which the actor inherits. The only problem for my purposes is that while commands of the form X, GIVE ME A KISS are remapped to ASK X FOR A KISS, commands of the form X, KISS ME are not. If nothing else works, there is always StringPreParser, but I was hoping for something a little more elegant.

OK, I figured out why GlobalRemapping caused a nil error. It’s because the kiss remap succeeds, but then transitions into the giveMeToAskFor remapping which fails for complicated reasons that I don’t fully understand. The fix I came up with was to track whether or not the GiveTo action being considered was already the result of a remapping, and if so to avoid a second remapping.

[rant][code]
kissToGiveKissTo: GlobalRemapping
getRemapping(issuingActor, targetActor, action)
{
if (action.ofKind(KissAction))
{
local newAction = GiveToAction.createActionInstance();
newAction.setOriginalAction(action);
newAction.setRemapped();
local dobj = new PreResolvedProd(kiss);
local iobj = action.dobjMatch;
newAction.setObjectMatches(dobj,iobj);
return [targetActor, newAction];
}

	return nil;
}

;

modify giveMeToAskFor
getRemapping(issuingActor, targetActor, action)
{
if (!(action.isRemapped()))
return inherited(issuingActor, targetActor, action);
else
return nil;
}
;

modify GiveToAction
isRemapped() { return remapped_ != nil; }
setRemapped() { remapped_ = true; }
remapped_ = nil
;
[/code][/rant]

This will remap all commands in the >KISS X form to the equivalent >GIVE KISS TO X form.

I’m not entirely sure if you want any remapping from >GIVE KISS TO X to >ASK X FOR KISS, however. That’s a little more difficult to accomplish, because it only holds when X is an actor and the kiss has to be transformed into a topic. I have a partial start on this but will happily abandon it unless it’s something you need.

This resolves the problem wonderfully. I would still like to remap orders to commands of the form ASK X FOR KISS, if at all possible. But this certainly gets me past the obstacle I had kept running into. Thank you.

Here’s a version that will remap >KISS X to >ASK X FOR KISS, when X is an Actor. Commands in the form >X, KISS Y will be likewise transformed into >X, ASK Y FOR KISS.

kissToGiveKissTo: GlobalRemapping
	getRemapping(issuingActor, targetActor, action)
	{
		if (action.ofKind(KissAction))
		{
			local dobjActor = nil;
			local obj = firstObj();
			while (obj != nil)
			{
				if (obj.ofKind(Actor) && action.canDobjResolveTo(obj))
					dobjActor = true;
				obj = nextObj(obj);
			}

			local newAction, dobj, iobj;

			if (!dobjActor)
			{
				newAction = GiveToAction.createActionInstance();
				dobj = new PreResolvedProd(kiss);
				iobj = action.dobjMatch;
			}
			else
			{
				newAction = AskForAction.createActionInstance();
				dobj = action.dobjMatch;
				iobj = new ResolveInfo(kiss, 0);
			}
			
			newAction.setOriginalAction(action);
			newAction.setRemapped();
			newAction.setObjectMatches(dobj,iobj);
			return [targetActor, newAction];
		}
		
		return nil;
	}
;

modify giveMeToAskFor
	getRemapping(issuingActor, targetActor, action)
	{
		if (!(action.isRemapped()))
			return inherited(issuingActor, targetActor, action);
		else
			return nil;
	}
;

modify TAction
	isRemapped() { return remapped_ != nil; }
	setRemapped() { remapped_ = true; }
	remapped_ = nil
;

It’s a bit clunky in performance terms because it has to iterate through every object in the game, check whether that object is an actor, and then check whether that actor could resolve as the direct object.

Transcript with results.

[rant]

[/rant]

This code worked pretty well, but it still did not transform commands in the form X, KISS ME into commands of the form ASK X FOR KISS. However, thanks to your code (especially your use of ResolveInfo(), which I was not familiar with), I was able to write this:

[rant]kissToGiveKissTo: GlobalRemapping getRemapping(issuingActor, targetActor, action) { if (action.ofKind(KissAction)) { local newAction, dobj, iobj; if (action.canDobjResolveTo(issuingActor)) { newAction = AskForAction.createActionInstance(); newAction.setOriginalAction(action); newAction.setPronounOverride(PronounYou, targetActor); dobj = new PreResolvedProd(targetActor); iobj = new ResolveInfo(kiss, 0); newAction.setObjectMatches(dobj, iobj); return [issuingActor, newAction]; } else { newAction = GiveToAction.createActionInstance(); newAction.setOriginalAction(action); newAction.setRemapped(); dobj = new PreResolvedProd(kiss); iobj = action.dobjMatch; newAction.setObjectMatches(dobj, iobj); return [targetActor, newAction]; } } return nil; } ;[/rant]

When I use this code, I get the responses I want from my NPC and no undesirable behavior (so far as I have seen).

Thank you so much! Without your help I would still be stuck in front of a number of obstacles.