punyinform. . Coding 2: Objects and Actions

punyinform. . 是一个用于为8位计算机和较新计算机编写文本冒险的工具。如果你已经了 安装punyinform.和gone through the punyinform. . Coding 1教程,时间来了解有关对象和操作的更多信息。本教程经过一个简单的游戏的不同部分,在那里有两个谜题可以解决,你可以得分,你可以赢得游戏。我的目标是解释这款游戏中的一切’T介绍了上一个教程。

游戏从房子外面的球员开始,他们认为他们的叔叔比利的意志可能是。他们需要穿过锁定的前门,然后通过另一个锁门的门来到达遗嘱的房间。那’s the whole game.

宣布常数

游戏代码第1部分

一个PunyInform游戏开始与一组常量说明游戏的名称是什么,您要使用的库的可选部分,以及更多。您通常需要在包括之前声明所有常量“globals.h”.

在第7行,我们声明我们希望在状态线中显示当前分数(和移动的数量)。其他选项是在状态线中显示时间,如“3:00 PM”。确保始终宣布所需的状态线。

在第10行我们说我们想使用Punyinform中的简单门机制。这使得更容易创建门。

Line 13-18 is about scoring. OPTIONAL_SCORED means we want to use the scored attribute as a simple way to give the player points when they pick up certain objects or visit certain locations. OPTIONAL_FULL_SCORE means we want to support the “full score” verb, giving the player a summary of the points. MAX_SCORE sets the maximum score. OBJECT_SCORE sets the number of points the player gets for each picked-up object that has the scored attribute, and ROOM_SCORE the number of points for each visited room that has the scored attribute. If you don’t declare OPTIONAL_SCORED these two constants have no effect.

然后我们包括“globals.h” and “puny.h”就像我们在朋比形象的比赛中始终一样。如果我们需要声明自己或写入的一些全局变量进入点例程,我们在纳入中这样做“globals.h” and “puny.h”。对于这个游戏,我们不’需要在那里写任何东西。

语法,动词和行动

游戏代码第2部分

punyinform. . comes with a standard set of verbs which most games need, like take, drop, open, lock, put, insert etc. Each verb has a 语法 –一个或多个线路,该行将如何由播放器使用,以形成导致的命令 行动 。不同的线条可能导致不同的行动,就像“put coat on shelf” triggers the action ##PutOn, but “put on coat” triggers the ##Wear 行动 (actions are (optionally) prefixed with ## to make them stand out in text and code).

在这个游戏中,我们’喜欢播放器能够敲门,而punyinform则没有’t有动词或行动。所以我们宣布动词‘knock’。每个语法线以*开头,添加任何介词,播放器必须键入,如果有的话,和“noun” to say that the player needs to specify an object. You can also write alternative prepositions, like this: * 'on'/'at'/'in' noun -> KnockOn. And you can specify two nouns like this: * 'on' noun 'with' noun -> KnockOn. The last grammar line must end with ; . Writing KnockOn-> 在 a grammar line means there is now an action called ##KnockOn and we will have to create a routine called KnockOnSub to handle this action, or we get a compilation error. Also note that dictionary words (words that we want to match against words typed by the player) must always be written with single quotes in Inform.

We’D也喜欢玩家可以在物体下看。这有点不同,因为punyinform已经支持动词‘look’。我们只想为语法添加一条线‘look’ verb. We do this with Extend. For this grammar line, we specify another new action called ##LookUnder. Of course, we’LL还需要创建一个名为lookundersub的例程来处理此操作。

现在我们进入行动例程。操作例程定义默认情况下的操作。每个行动都属于三组中的一个:

  • Group 1: Meta-actions that do something to control the game itself, like ##Save (which saves the current state of the game to a file) and ##Score (which prints the player’s score).
  • Group 2: Actions which change something in the game world or print some important information about it, like ##Take (which moves an object to the player’s inventory) and ##Inv which lists the player’s possessions.
  • 第3组:默认情况下的行动’t do anything but print a message essentially refusing to do it or saying it has no effect, like ##Swim, ##Push##Yell.

You can change what group 2 actions and group 3 actions do for certain objects by adding before routines to these objects or to the room where the action happens. You can also choose to let any other object present react using a react_before routine. If any of these routines return true, it means the default behaviour of the action is cancelled, and the action routine won’t even be called.

For group 2 actions, you can also use an routine in the object affected or the room, or a react_after routine in any other object present to do something special and/or print a custom message 这一行动发生了。如果例程返回True,则动作例程获胜’t print anything.

您添加到游戏的大多数操作往往是第3组行动。这里指定的这两个操作都是第3组操作。这意味着动作例程应该只打印默认消息’s it.

外面的地方

游戏代码第3部分

让’s开始定义游戏对象。首先是草坪位置。没有什么新鲜事。然后是’s正射位置。这里唯一的新概念是出口可以导致门对象而不是位置。我们’LL覆盖在下一节中。

使用parse_name.

游戏代码第4部分

Now to the door mat, and this is where it gets intersting. It may look like we could just have added name 'door' 'mat', to the properties, but that would get us in trouble. See, there’在这个位置的前门(进一步宣布),然后是这个门垫。如果玩家类型“open door” or “examine door”, we don’想要解析器问“你的意思是哪一个,前门或门垫?”. So, we give the DoorMat object a parse_name routine. This is a routine which can read words from the player input using NextWord()和return how many words in a row match this object. This specific routine returns 2 (meaning it matched two words) if the player typed “door mat”或者,如果播放器键入,则失败,它会返回1“doormat” or just “mat”。如果播放器键入其他任何内容,则例程返回false(其等于0),这意味着没有任何匹配。

属性中的例程,如此,默认情况下返回false / 0,而命名例程(如上一节中的操作例程)默认返回true / 1。

In line 55 the routine starts with [ . After that we can name up to 15 local variables we want to use in this routine. These are also used as parameters, that is they get assigned values if someone calls the routine with one or more arguments. We choose to create two local variables named w1 and w2. The ; marks the end of the local variable list. A local variable is a variable that is created when the routine is called and destroyed when the routine returns. It only exists within the routine, and it can’T从任何其他例程以任何方式访问。不同的例程可以具有相同名称的局部变量,没有困惑的风险。

In line 56 and 57 we assign values to these two variables. Assignment is done with a single = . On the righthand side we call the function NextWord and use its return value. The parenthesis mean “用我刚刚给出的名称致电例程”。如果要将参数发送到例程,则将它们放入括号内,并在它们之间使用逗号。

In line 58 we see == which is used to check if a value equals another value. We also see the operator && which means AND, so the if-statement checks if the first word is ‘door’第二个词是‘mat’. Additionally, Inform has the operators || meaning OR and ~~ meaning NOT.

In line 59 we see another neat trick in Inform: the keyword or. It can be used when comparing one value to multiple other values, and it generates shorter and faster code than doing the comparisons one by one. Line 59 is functionally equivalent to:

if(w1 == 'doormat' || w1 == 'mat') return 1;

隐藏门垫下的钥匙

那里’S隐藏在门垫下的钥匙。自钥匙可以’看看,我们实际上是不是’T刚刚将钥匙放在位置,但玩家应该能够找到它。所以,我们希望Doormat对象有两种方式特别:

  • 如果播放器在垫子下面看起来或拉开垫子,他们应该找到钥匙。
  • 要避免将许多玩家尝试的标准操作之一暴露关键,如“take all”,我们想阻止玩家拿起垫子。

We accomplish this with the before routine. First, we react to the ##Take##Remove actions. Actually just ##Take would have sufficed here, but ##Take##Remove are the only two actions you ever need to consider if you want to stop an object from entering the player’s possession, so I usually type out both (##Remove is used when an object is removed from inside a container or on a supporter).

打印响应并返回true

The syntax on line 63 and 68 where we just type a string enclosed by doublequotes is a shorthand for the print_ret command, which means “打印此选项,然后打印换行符,并返回true”。所以这四条代码实际上是等同的:

四种做同样的事情

看着垫子

然后让我们’s look at the second part of the before routine. If the action is ##LookUnder or ##Pull, we check if MetalKey has the parent 0 –这意味着它有 ’t been brought into the game yet. If this is true, we move the key to the current location (location is a global variable holding the object ID of the current location), we increase the score by 10 points, we print a message and return true. If the condition isn’t met, the routine will return false and the action will respond with its default message. Note that whenever we want an if-statement to perform more than one command, we must enclose these commands in { } like we do on line 65-69.

Finally, this object has two attributes: supporterenterable. The first means there can be objects 这个对象。后者意味着使用诸如的命令,玩家也可以在此对象上“sit on mat” or “enter mat” to get on.

钥匙

游戏代码第5部分

Now we define the key. Since there is no ->Object the key won’t放在最后定义的位置,但它’s rather hanging in limbo, not in or on anything, when the game starts. The only news here is the scored attribute. This means the player will get a certain number of points when they first pick it up. The number of points is the value of OBJECT_SCORE , given on line 17.

前门

游戏代码第6部分

现在它’时间定义我们的第一扇门。我们’ll使用punyinform’s Simple Door mechanism, since this makes the code simpler and most of the time it covers the needs. A door in PunyInform is any object which has the attribute. A door is a gateway between locations. It typically exists in two locations and provides a means for going from the first location to the second or from the second location to the first.

when_openwhen_closed play the same role as 在 itial but for doors and containers only. That is, the object gets a paragraph of its own in the room description. If the object is open, when_open is used, otherwise when_closed is used. In this case, we want the when_open text to be different depending on if we’re seeing the door from the outside or the inside of the house, so we use a routine. For when_closed we’只需静态串即可。

敲门,谁’s there?

现在是我们创造的原因‘knock’ verb and the ##KnockOn 行动 earlier: We want to give a proper reply if the player tries to knock on the front door, since that seems a quite sensible thing to do. We do this with a before routine. If the action is ##KnockOn , we print a message and return true, thus stopping the default message from printing.

浮动物体

在任何时间点,每个对象都只能在一个位置,但是PunyInform在玩家移动时具有用于移动物体的机制,因此在若干位置可以存在对象。这有时被称为浮动物体和is controlled with the found_in property. The value of found_in should be either a routine which returns true if the object should be in the current location, or a list of locations where it should be (You will notice that a list of values in Inform is also referred to as an 大批 在文档中)。

If we want to use the Simple Door mechanism for a door, that door has to have a found_in property, and its value must be an array with exactly two values. In this case, we place the door in FrontPorch and Entrance.

做门工作

A door has to have a 门_dir property, to say in which direction a door lies. For a regular door, this should be a single value or a routine, and you usually need to write a routine which returns different values depending on the current location. If you use the Simple Door mechanim, and the door has an array with two values in found_in , you can just give an array with two values here. If the player is in the first location in the found_in array, the first value is used, otherwise the second value is used. We use parenthesis around the values to avoid a warning from the compiler.

For a regular door, we also have to provide a 门_to property, saying where the door leads. This too should be a single value or a routine. For a Simple Door, we can just skip it. If the player is in the first location in the found_in array, the door leads to the second location in the array and vice versa.

For an object which is lockable, the with_key property is used to say which key fits the lock.

Then come the attributes. We use static to say that this object is fixed in place and can´t be picked up by the player. We use to say it’s a door. We must add openable to say it can be opened and closed and lockable to say it can be locked and unlocked. Finally we add locked to say the door is locked from the start. And that’它,我们有一个完整的门!

添加一个可输入的容器

游戏代码第7部分

这里’s the definition of Entrance, the room inside FrontDoor. You can also see that one exit leads to FrontDoor, and one leads to another door called OfficeDoor. This location has the scored attribute, which means the player gets a certain number of points when they first come here. The number of points is the value of ROOM_SCORE , given on line 18.

这个位置有几个有趣的物体。我们从玻璃盒开始。像你一样’很快就会看到,这个位置有几个盒子。允许玩家立即引用所有这些,这是有道理的,如“take the boxes”。为了支持这一点,我们添加了这个词‘boxes’ to the name property, only we add the plural flag to it, to say it’s的复数形式,如下所示:‘boxes//p’.

此外,我们’re making this box enterable, and we want to add a description for when the player is inside the box. We do this with 里面 _description. This can also be used for enterable supporters.

如果玩家试图在周围移动盒子,我们想告诉他们它’真的很重,所以我们在例程前添加一个捕获用于移动事物的常用动作。

We proceed to the attributes. This is a static object, which means any attempts to take or move the object gets a reply like “It’s fixed in place.” (only we’选择在常规之前覆盖所有或大多数或大部分)。它’s a container, meaning other objects can be inside it. openable means it can be opened and closed. enterable means the player can enter the object. transparent means it’s透视,这意味着我们即使在它的时候也可以查看内容’已关闭,如果有些东西在外面露出光明’S也亮了内侧,反之亦然。

项链

游戏代码第8部分

Now we add a necklace. It has two arrows ( -> ) after Object, which means it is 使用单个箭头定义的最后一个对象,在这种情况下,玻璃盒。

玩家应该能够打破项链以释放宝石。我们在常规之前做到这一点。我们’ll需要一个局部变量,我们’ll call it loc (short for “项链的位置”). We capture the ##Attack action, which is what we get if the player types “break necklace”, “destroy necklace” or “wreck necklace”. First we use the PunyInform routine ObjectIsUntouchable to check if the necklace is untouchable by the player. If it is, ObjectIsUntouchable prints a message telling the player why they can’t reach the necklace, and we return true to tell PunyInform not to do or print anything further. Note that we use 名词 here, which is always set to the primary object of the current action. When we’在常规之前(至少一个不起作用)’t belong to a room), 名词 has the same value as self, so we can use them interchangably. As we have now decided that the player can reach the necklace, we perform a sequence of commands:

  1. We set loc to the current parent of the necklace. This could be the glass box where we found it, but it could also be the player, or it could be the Entrance location etc.
  2. We then remove the necklace, meaning we remove it from the object tree and put it in the void where the player will never see it.
  3. 接下来,我们将是项链的一部分的三个宝石移动到项链的位置。
  4. 我们增加得分
  5. We print a message and return true, signaling that PunyInform should not print the default message for ##Attack.

项链 has a single attribute: transparent . This is there to signal that if there are objects 这个对象,他们可以看到播放器。将对象放置在其他对象中的对象意味着根据父对象的对象类型:

  • 对于容器(袋子,盒子,汽车等),这意味着它的物体实际上是 里面 容器。
  • 对于支持者(床,桌子,地毯等),这意味着它中的物体支持者。
  • 对于动画对象(一个人,动物,机器人等),它意味着它中的对象是 握住 通过动画对象。
  • 对于所有其他对象,它意味着对象是 部分 对象,如按钮是收银机等的一部分。

最后一个案例是我们的’在这里处理。看看下一块代码来看是那些的宝石 部分 项链。

宝石

游戏代码第9部分

我们现在添加了三个宝石。三个箭头意味着他们’re in (meaning 部分 )我们刚定的项链。这三个都有多个词‘gems’ added to their name property, so the player can “take gems”。翡翠需要无限的文章“an” and so we give it the property 文章 和the desired article as a string.

将宝石放在项链中,如此意味着他们在项链的任何地方都走了,玩家可以检查宝石,但如果他们试图拍摄他们的一个宝石,他们就会得到一条消息’项链的一部分。

办公室门锁

游戏代码第10部分

除了带有项链的玻璃盒外,还有一个蓝色的盒子和一个绿色盒子,附着在办公室门旁边的墙壁上。这些实际上是办公门的锁定机构的一部分。如果你在绿色盒子里的蓝色盒子里和祖母绿的蓝宝石,门被解锁了。然而,使这种情况发生的代码不在盒子里,而是在门本身。

定义框的代码唐’t hold many surpises. The only thing new here is the describe property. This is used when you 可能 想要在房间描述中打印一个对象的文本段落。如果您这样做,您打印换行符,您喜欢的任何文字,另一个换行符,然后返回true。如果你决定不要’要为此对象打印一个单独的段落,返回false。但是在那里’你可以在这里做的诀窍:唐’t打印任何东西,但返回true。这将停止“look” from printing anything about the object at all. The boxes are mentioned in the description property of the room, so we don’想要比赛再次向他们展示。

办公室门

游戏代码第11部分

玩家可以在蓝色和绿色框中放置各种物体。每当玩家在别的东西中插入了某些东西时(“把祖母绿放在绿色的盒子里” triggers an ##Insert action), or picked something up, we want to check if the conditions are met to unlock the door. When we want an object (in this case the office door) to react to an action that happens nearby but where this object may not be directly involved, we can use react_beforereact_after. They work very much like before. We can use 名词second to check which primary and secondary nouns are used in the action. In this case, we don’但是需要它。我们检查是否满足以下条件:

  • 蓝宝石在蓝盒子里
  • 那里 is exactly one object in the blue box
  • 翡翠是在绿色的盒子里
  • 那里 is exactly one object in the green box
  • 门被锁定了

如果满足所有这些条件,我们:

  1. 解锁门
  2. 给玩家一些点
  3. 打印邮件并返回true,这意味着punyinform需要’t print anything

Unlocking the door is done by setting the locked attribute to 0 for the OfficeDoor object. An attribute is a bit value –它可以是0或1.这是您可以使用属性执行的:

  • You can check if attribute locked is 1 for object X with if(X has locked)
  • You can check if locked is 0 with if(X hasnt locked)
  • You can set locked to 1 with give X locked
  • You can set locked to 0 with give X ~locked

The rest of the definition of this object is very similar to the front door. One difference is that while it has the lockable attribute, it doesn’t have the with_key property. This means the player can tell the door is locked, but there is no key that can unlock it using the “unlock” verb.

最后的位置

游戏代码第12部分

我们已经来到了办公室的最后一个位置。我们描述了一张桌子和椅子,但他们’真的不是那么重要,所以我们’d rather not implement them as objects. Instead we put these words in the name property of the location, so the player gets a message saying they don’如果他们尝试与它们交互,则需要引用这些对象。

The will has the 在 itial property meaning this string will be printed as a paragraph of its own when the player views this room, as long as the object hasn’搬了。如果播放器占据遗嘱并再次删除它,则它将与该位置中的任何其他常规对象一起列出。

然后那里’s the description of course. If the player tries to examine or read the will, the description property is consulted. If it’■常规,它是运行的。所以这是我们结束游戏的好地方。这就是我们所做的:

  1. We set deadflag to GS_WIN (which is 2, but it’s easier to remember GS_WIN) (“GS” stands for Game State by the way, since this variable controls if the game goes on or if it ends). If you set it to GS_DEAD instead, the game ends as well, but with a message saying the player has lost.
  2. 我们增加得分。
  3. 我们打印了对意志的描述。 (只需在双引号中编写一个字符串,如此意味着我们也打印一个换行符,这是好的,并返回true’t matter –预期说明属性始终始终打印描述,并且简单地忽略其返回值。)

在行动完成后,DeadFlag现在的通知现在GS_WIN并结束游戏。

初始化的例程

游戏代码第13部分

最后,它 ’编写强制性初始化例程的时间,在游戏开始时调用。我们可以使用这个例程来移动事物,开始定时器等,但对于这个游戏我们所需要的只是打印介绍游戏。

完成的比赛

游戏正在播放

将游戏编译为Z代码文件后,您可以播放您选择的Z代码解释器。上面的屏幕截图来自Windows Frotz。

链接

Fredrik Ramsberg.

文字冒险粉丝,球员和作者自8岁以来。当前项目包括OzMoo(C64的Z代码解释器)和PunyInform(一个轻量级Invegn 6 Liftill,用于为8位平台和较新计算机编写文本冒险)

发表评论

您的电子邮件地址不会被公开。必需的地方已做标记*

本网站使用AkisMet减少垃圾邮件。了解如何处理评论数据.