Inform 7 Home Page / Documentation
§7.5. Combat and Death
Not all characters are friendly, and there are times when we may want to include a fight sequence. There are a number of ways to approach this, depending on whether we want to offer the player a random outcome, a predetermined one, or a combat sequence that depends partly on strategy or on having the proper equipment.
Lanista 1 demonstrates randomized combat in the style of a role-playing game. The player has a partially random chance of doing any given amount of damage; both the player and his opponent have hit points, and whichever one runs out first dies. Lanista 2 continues this idea, but includes weapons that affect the amount of of damage done. Red Cross by itself implements a command that we might use to find out how strong characters are at the moment.
A word of warning about designing such sequences: a player who gets a roll he doesn't like always has the option of UNDOing a turn and re-rolling. This means that he can always win a random battle sooner or later; bad luck only means that it takes him longer (so he gets more bored and irritated as he plays through). It is possible to turn off UNDO implementation with
Use UNDO prevention.
...but there is a good chance that this will irritate players in itself. Role-playing-style combat scenarios need careful design, lest they actively make a story less fun.
In a slightly more realistic setting, combat leaves physical remains behind, unless we're wielding some kind of futuristic weapon that evaporates our opponents entirely: Puff of Orange Smoke demonstrates characters who leave corpses behind when they die, while Technological Terror more tamely explodes robots into numerous component parts.
Finally, we can imagine some scenarios in which, instead of allowing characters to strike at each other for random damage, we want to introduce an element of strategy. Don Pedro's Revenge shows the rudiments of a system in which the characters can make different kinds of attack depending on where they are in a room filled with perches, barrels, and other swashbuckler props.
See Saving and Undoing for more discussion of handling random behavior in games
|Start of Chapter 7: Other Characters|
|Back to §7.4. Barter and Exchange|
|Onward to §7.6. Getting Started with Conversation|
The Arena is a room. "Sand, blood, iron. These festivals are normally held on hot days, but the sun has gone behind a cloud and fat drops of rain now and then spatter the arena floor." The gladiator is a man in the Arena. "A bare-chested Scythian gladiator faces you, wielding a trident."
We start by recording, for each person, a maximum number of points of damage the person can sustain when starting from health, and the current number of points remaining. In the tradition of role-playing games, these are referred to as hit points.
Now our rule for the actual attack. We want first to calculate how much damage the player's attack does, inflict that damage, and remove the enemy if he's dead; then, if he doesn't die, the enemy counter-attacks, also for a randomized amount of damage, and if this kills the player, the game ends in defeat.
Instead of attacking someone:
let the damage be a random number between 2 and 10;
say "You attack [the noun], causing [damage] points of damage!";
decrease the current hit points of the noun by the damage;
if the current hit points of the noun is less than 0:
say "[line break][The noun] expires, and is immediately carried away by the Arena slaves!";
now the noun is nowhere;
end the story finally;
stop the action;
let the enemy damage be a random number between 2 and 10;
say "[line break][The noun] attacks you, causing [enemy damage] points of damage!";
decrease the current hit points of the player by the enemy damage;
if the current hit points of the player is less than 0:
say "[line break]You expire!";
end the story.
This last bit is a refinement to help the player keep track of how the contest is going:
Puff of Orange Smoke
Suppose we want to let the player kill characters, leaving behind corpses.
Paraguay is a room. Bolivia is north of Paraguay. Lydia is a woman in Paraguay. "Lydia is, as usual, here." The description of Lydia is "Long, long legs and a sarcastic attitude." Instead of touching Lydia: say "'Watch it, sailor,' she snaps."
Using our "part of every person..." line, we've conveniently assigned one body per person. Since we're going to separate people from their bodies when the bodies die, though, we also want a more permanent relation that will help us keep track of which bodies used to belong to which people:
When Lydia is alive, we want >TOUCH LYDIA'S BODY to mean the same thing as >TOUCH LYDIA, so we use the setting action variables rules as a convenient point at which to reassign the action:
This doesn't change Inform's idea about what action is being performed; just about the object it's being performed on. The rest of the action will now proceed as if the player had typed >TOUCH LYDIA.
Along similar lines, once Lydia is dead, we want >MOVE LYDIA to mean >MOVE LYDIA'S BODY if the body is in view:
The trick is, though, that >MOVE LYDIA will only be understood if there is something called Lydia that the player can see and refer to, even after she's dead. There are various ways to do this, but the least painful here will be to make the deceased Lydia permanently visible, by putting her in an always-accessible backdrop. The backdrop itself will never be mentioned in the game, and we should make its name something that the player is unlikely to type casually; we don't want the player to interact with it directly. So:
It's also possible that the player will type something like >X LYDIA when Lydia's corpse is not in view, so we should have an appropriate answer to that as well:
Because the before rules happen after the setting action variables rules, this will only ever happen if the corpse is not visible.
Now we define the attack itself, which should discard the body, move the spirit to its eternal resting place, and describe the event to the player:
Instead of attacking someone:
let the corpse be a random body which is part of the noun;
move the corpse to the location;
move the noun to the spirit-world;
say "With a single blow, you rid the world of [the noun]."
And finally a trick borrowed from the chapter on understanding, so that we can refer to "Lydia's body" while Lydia is alive, but "Lydia's corpse" only after Lydia has died:
Back in the chapter on randomization, we explored a way to create a randomized combat system. That system didn't allow for multiple weapons, though. Here we explore how to create an ATTACK IT WITH action that will let the player choose between weapons with different maximum powers.
We're also going to rewrite that original "instead of attacking:" rule into an attacking it with action that can be performed equally by the player or by any of the player's enemies.
The Arena is a room. "Sand, blood, iron. These festivals are normally held on hot days, but the sun has gone behind a cloud and fat drops of rain now and then spatter the arena floor." The gladiator is a man in the Arena. "A bare-chested Scythian gladiator faces you, wielding [a list of weapons carried by the gladiator]."
In our simpler version of this example we set the current hit points by hand, but in a game with many characters this would get dull and repetitive, so here we'll use a "when play begins" to set all current hit point values automatically to maximum:
Carry out diagnosing:
say "[if the noun is the player]You have[otherwise][The noun] has[end if] [current hit points of the noun] out of a possible [maximum hit points of the noun] hit points remaining."
In our new system, we want to specify what is being used for an attack. This means that we need to create a new "attacking it with" action, and also that we should disable the existing "attacking..." command.
Here's why: If we leave the default attack command in place, Inform will continue to accept commands like >ATTACK GLADIATOR, but reply foolishly with the default "Violence is not the answer..." response.
A somewhat better approach would be to change the reply of >ATTACK GLADIATOR to say something like "You must specify a weapon to attack with." But this is still less than ideal, because it means that the player has to then rewrite his entire command. If, on the other hand, we take out "ATTACK GLADIATOR" entirely, the game will always prompt "What do you want to attack the gladiator with?" -- which teaches the player the correct command structure for this particular game, and avoids pretending to understand any command that is not meaningful within this game.
This is a little bit of work because ATTACK has a lot of synonyms in the default library, but if we look through the actions index we can find them all:
Now we make our new command:
Note that we've specified "one carried thing", because we want the player to pick up a weapon to use if necessary. And now we assign all the old attack vocabulary to apply to the new command:
This may seem counter-intuitive, but order of source code matters here: we first get rid of the old, default vocabulary, then define our new action, then make the vocabulary apply to that new action. Inform will now understand >HIT GLADIATOR WITH TRIDENT, >BREAK GLADIATOR WITH TRIDENT, and so on.
Our new action is also a perfect place to use an action variable: we're going to need to choose an amount of damage done and refer to that several times in our action rules. So let's set that up first:
Setting action variables for attacking something with something:
if the second noun is a weapon:
let the maximum attack be the maximum damage of the second noun;
now the damage inflicted is a random number between 1 and the maximum attack.
Check an actor attacking something with something (this is the can't attack with something that isn't a weapon rule):
if the second noun is not a weapon:
if the actor is the player, say "[The second noun] does not qualify as a weapon.";
stop the action.
Check an actor attacking something with something (this is the can't attack a non-person rule):
if the noun is not a person:
if the actor is the player, say "[The noun] has no life to lose.";
stop the action.
Carry out an actor attacking something with something (this is the standard attacking it with a weapon rule):
decrease the current hit points of the noun by the damage inflicted;
if the noun is dead and the noun is not the player:
now the noun is nowhere.
Though our checks and carry-out rules are similar regardless of who is acting, we're going to want actions to be described differently for different actors, so we'll use separate "report attacking" and "report someone attacking" rules. We'll also make some special cases for when the character has died as a result of the attack:
Report someone attacking the player with something when the player is dead (this is the player's-death priority rule):
say "[The actor] attacks you with [the second noun], finishing you off!";
end the story;
stop the action
Report someone attacking the player with something (this is the standard report someone attacking the player with rule):
say "[The actor] attacks you with [the second noun], causing [damage inflicted] point[s] of damage!" instead.
Report someone attacking something with something (this is the standard report attacking it with rule):
say "[The actor] attacks [the noun] with [the second noun], causing [damage inflicted] point[s] of damage!" instead.
Those devoted to role-playing will note that our form of randomization is still pretty naive: most RPG systems use multiple dice in order to create more interesting probability curves. For a system that simulates actual dice-rolling, see the full "Reliques of Tolti-Aph" game.
Don Pedro's Revenge
Suppose our game features a detailed simulated combat between the player character and his opponent. He might have several weapons available, and several types of attack available; and at any given time he might be perched up in the rigging of his ship, standing on the open deck, or boxed in between some barrels. His options will vary depending on his position, and obviously it would detract from the pacing to make the player keep LOOKing in the middle of combat in order to remind himself where he is. Instead, we'll roll this information into the command prompt:
"So securely boxed-in that you can really only parry or thrust, you try to "
"Trapped between your barrels, you decide to "
"Able to slice at your attackers but not to advance or retreat, you choose to "
"Perched up here with the advantage of height (but little mobility), you attempt to "
"Out on the open deck with no impediments, free to advance or retreat, you decide to "
To reset the prompt:
sort the Table of Random Prompts in random order;
repeat through the Table of Random Prompts:
if the position entry is the placement of the player:
now the command prompt is prompt entry;
Of course, this won't be much fun until we also provide the player with a few weapons, some more fighting maneuvers, and, most of all, a Don Pedro to defeat.
First we need to define our shooting action:
Check shooting something with something:
if the player is not carrying the Ray Gun, say "You are pathetically unarmed!" instead;
if the second noun is not the Ray Gun, say "[The second noun] does not fire." instead;
if the noun is the Ray Gun, say "Nice trick if you can do it!" instead;
if the noun is the player, say "That would be disastrous!" instead.
Next, some grammar to allow the player to use this action:
Understand "shoot [something] at [something]" as shooting it with (with nouns reversed). Understand "fire [gun] at [something ungunlike]" as shooting it with (with nouns reversed). Understand "fire at [something ungunlike] with [gun]" as shooting it with. Understand "fire at [something] with [something]" as shooting it with.
Strictly speaking, we only need these last grammar lines (with "understand shoot something...") in order to define an action that the player can take. Adding more grammar lines means that Inform will try to match the most specific ones first, which is useful when the player types something ambiguous and there is one choice that obviously fits this action better than the others. See the chapter on Understanding for a further discussion.
Here we get to use "now..." to give it its destructive effect:
Carry out shooting something with something:
say "ZAP! [The noun] twinkles out of existence! [if something is part of the noun][The list of things which are part of the noun] clatter to the ground! [end if][paragraph break]";
now every thing which is part of the noun is in the location;
now the noun is nowhere.
The Deathbot Assembly Line is a room. "Here is the heart of the whole operation, where your opponents are assembled fresh from scrap metal and bits of old car." The dangerous robot is a thing in the Assembly Line. "One dangerous robot looks ready to take you on!" A robotic head, a drill arm, a needle arm, a crushing leg and a kicking leg are parts of the dangerous robot.