Preventing UNDO

I realize this may be tinkering with some seriously core functionality, which is why I’m asking here if anybody has a quick idea before I dive in just to end up with a boatload of useless code.

Simply put, I have some events that become too trivial if the player can UNDO any action to get a better (randomly generated) result. What I wish is to disable the command’s availability when specific conditions are met (Specifically, any turn a certain type of custom Actor is present in the same room as the player and its AgendaItem is being executed). For any other time, I am perfectly fine with it.

I realize save-scumming would achieve the same result as UNDO in this case, but I can accept that. Constant saving and reloading is a bit more tedious, so if the player is willing to take the trouble to cheat, I’m okay with it. I just don’t want to make it simple enough that one typed command will do.

So… too crazy?

UNDO is an action like any other, and therefore can be customized like any other. It doesn’t have any kind of special status.

You might think about using transient objects to store the values you want to preserve across UNDO and RESTORE.

If your scenes are well-defined - attempt #N to slay the Majestic Horned Owl - you could have a non-transient counter that gets incremented after each attempt, and a transient lookup table with the attempt counter as key and the outcome as value. Then before rolling a random result for attempt N, check the table to see if an outcome for that attempt exists and if so return it.

Blocking undo is an option but you should consider how often players might try the command. If the only time they attempt to undo is after one of these failures, then it will feel as though you have disabled undo completely. If that’s the case, consider doing just that. Lack of undo is frustrating but an undo that only works in trivial situations is perverse.

I forgot to mention that randomness is still random even with UNDO. If you roll the dice, then UNDO (or SAVE/RESTORE) and roll again, the results will be different.

This is only true of course if you roll the dice when needed, rather than saving the results of a lot of rolls beforehand and using those results later.

I’ve solved most of the issues and got this to work the way I intended, though I don’t really like WHERE I put the code.

In order to insert a check that would enable or disable UndoAction depending on certain circumstances, I had to go directly into action.t and mess with the action’s definition. Specifically, where it said:

           /* perform the undo */
           performUndo(true);

Now it says:

        /* perform the undo */
        if (certainActor.location == gPlayerChar.location)
        {
            "Command disabled. ";
        }
        else
            performUndo(true);

The actual check is a lot more complicated, but this is just to illustrate. Is there some way to do this from the outside, so as not to mess with the basic libraries?

That’s precisely the reason I wanted to disable the action. There are plenty of other situations in my game were users may want to undo their actions and I have no problem with that. The issue here is that there are situations where there’ll be a quick succession of random rolls that I want to force players to deal with no matter how they come up, rather than allowing them to comfortably reroll each one until they get the results they prefer. I’m fine with them starting over from the beginning of the event (It’s not long) and if they want to use more tedious forms of cheesing, I won’t stop them. I just don’t want to end up in a situation where the most efficient method of playing is rerolling each roll until they get the result the want, because at that point the random element becomes only a timewaster and I might as well jus scrap it and give them the best result automatically.

Yes, by overriding the method in your own sources, using the ‘modify’ keyword. Try:

modify UndoAction {
    doAction(issuingActor, targetActor, targetActorPhrase, countsAsIssuerTurn)
    {
        if (certainActor.location == gPlayerChar.location) {
            "Command disabled. ";
            return;
        }
        inherited(issuingActor, targetActor, targetActorPhrase, countsAsIssuerTurn);
    }
}

What this does is do nothing (other than printing “command disabled”) if your check is true, but call the original method otherwise.

As a player, I’d rather keep UNDO. As a programmer, I’d rather not add a check to only undo if you’re not in a certain area.

…Which is why I’d try a third option. RealNC mentioned it, and I think it’s the best bet:
Roll all the dice at the start of the first event, instead of at the start of each event.
Thus, UNDO will work fine for everything outside the events, and inside the events, the player will only “roll the dice” if he uses UNDO (or LOAD, or whatever) to go back to a point before the first event. As long as you have more than two or three events, the chances of using UNDO to get all the events “good” is incredibly low.