PunyInform编码3:守护进程和描述对象

查看本文的底部,以获取与其他文章和PunyInform上的教程的链接。如果您按顺序浏览它们,这些教程最有意义。

在本教程中,我们’修复你的游戏’重新努力莫里斯夫人。它 ’这是一天结束,你想回家。所有你所要做的就是微波炉一盘意大利面,以适当的温度进食并将其放在哑剧师。然后你可以离开。

宣布常数

PunyInform代码第1部分

在第7行,我们声明我们希望在状态线上显示时间线而不是分数。

第11行:我们希望玩家能够“将(对象)设置为(数字)”。这包括在扩展的verbset中,所以我们’LL只是添加该选项。我们也得到了一堆其他漂亮的动词。如果文件规模是我们的重大关注,我们可以定义动词‘set’ by hand, but it’s not.

第12行:除了用数字播放器型号,我们可以允许它们为少量使用单词,因此玩家可以键入“set timer to five”.

第13行:我们决定我们不’t need a scoring system for this game. Defining NO_SCORE drops the verbs and actions for showing the score, as well as the messages telling the player the score has gone up or down etc.

进入点例程, extensions and grammar

PunyInform代码第2部分

定义所有库常量后,它’是时候包括全局。在此之后,我们创建了自己的全局变量。 PunyInform程序可以定义最多约150个全局变量。这可以很有用来跟踪游戏中发生的事情等。我们为此特定变量提供了名称“f_” to mark that it’s a flag –只能具有值true(1)或false(0)的东西。当游戏开始时,玩家还没有为莫里斯夫人提供一顿饭,因此标志从价值为false开始。

punyinform.支持一套“Entry point routines”(看看其中的哪些punyinform.手册和read up on what they do in the 设计师’s Manual). If you want to define any entry point routines, you need to do so before including puny.h. One of these routines is DeathMessage.

If at any time we want to end the game, we set deadflag to a value greater than 0. The value 1 (also referred to as GS_DEAD) means the player died. The value 2 ( = GS_WIN) means the player won. Values greater than 2 are used when we want to add our own ways of ending the game. If we use a value greater than 2, we must also add a DeathMessage routine which checks the value of deadflag和prints a message.

在第26行,我们包括一个调用的分机“ext_waittime.h”。这允许玩家键入类似的东西“wait for 10 minutes” or “wait until 9 pm”.

动词‘set’可以用两种方式使用:“set (object)” or “将(对象)设置为(数字)”. For our game, it’如果我们放弃表格,更好“set (object)”并添加另一种形式:“将(对象)设置为(数字) minutes”. When we want to remove some part of the grammar for a verb, we need to replace the entire grammar for that verb. This is what we do in line 28-30. Note the keyword replace.

在第32-36行中,我们添加了表达的新方法“switch on (object)” and “switch off (object)”, namely “start (object)” and “stop (object)” respectively.

厨房

PunyInform代码第3部分

厨房是这场比赛中一切都发生的位置。

If the player tries to go north, we supply a routine to decide on the outcome of this action. If they have served Mrs. Morris her meal, we return Street, which is of course a location. Otherwise, we print a message saying why the player can’去北方并返回真实。

笨蛋–赢得和失去的票

PunyInform代码第4部分

笨蛋is a container which is always open. To give it a paragraph of its own in the room description, we give it the when_open property. In this routine, we print that there’s a dumbwaiter here, and then we perform the action ##Search with the noun self. We do this with the angle bracket notation on line 58. This means the game will print whatever it would normally print if the player had typed “搜索笨爪”,意味着它会说什么’s in the dumbwaiter.

Then we have a before routine, to handle the player putting things in the dumbwaiter. As you already know from previous tutorials, a before routine can react to the actions the player types. It can also react to actions performed in code, like ; . Additionally, some actions issue “fake actions”。假行动是一种行动’T有一个动作例程,没有语法指向它。这些是PunyInform可以发布的虚假行为:

  • The ##Insert action issues a ##Receive fake action to the object the player tries to put something in. While this fake action is happening, receive_action has the value ##Insert.
  • The ##PutOn action issues a ##Receive fake action to the object the player tries to put something on. While this fake action is happening, receive_action has the value ##PutOn.
  • The ##Take action issues a ##LetGo fake action to the object the player tries to remove something from.
  • The ##ThrowAt action issues a ##ThrownAt fake action to the object the player tries to throw something at.
  • The ##Go actions issues a ##Going fake action to the location where the player is about to go.

所以即播放器类型“put banana in box”, the banana can react to the ##Insert action, and the box can react to the ##Receive action. In the game we’重新编写,这是我们在玩家试图在笨蛋中放置某些东西时所做的事情:

  • 如果名词不是’t the spaghetti, it’s simply denied –我们打印一条消息并返回true。
  • 我们打印播放器将意大利面放在笨蛋中。
  • 我们检查意大利面的温度,除以六个。 (任何剩余的被扔掉)
  • 如果它’s less than 2, it’太冷了。玩家需要更多地加热食物。
  • 如果它’s more than 2, it’太热了。播放器被解雇,游戏结束。
  • Since at this point it has to be two, we note that the player has indeed served Mrs. Morris a satisfactory meal (by setting f_served_meal to true), and can now go home. We also remove the spaghetti from the game, and print a message.
  • 请注意,无论发生什么,我们总是返回真实,从而阻止了动作。这意味着没有任何东西在笨蛋中没有任何东西。虽然我们可能会打印播放器将意大利面放在笨蛋中,但我们不’实际上必须这样做。

微波炉,第1部分

PunyInform代码第5部分

微波炉是一个非常复杂的物体。在这里,我们看到第一部分,第二部分是下一个图像。那里’S也是烤箱的计时器,稍后会出现。

First, we want to tell the player about the oven in the room description. While there are specific properties like when_openwhen_closed, there’s always the more generic describe, and this seems more suitable here, since not only do we want to say if the oven is open or closed, but also if it’s on or off and what’s inside it.

Then comes the before routine, which reacts to the ##SwitchOn action. If the oven is already on, we don’T需要反应。行动程序将告诉玩家烤箱已经打开了’就像我们想要的方式一样。因此,我们返回错误。现在,如果烤箱关闭并打开,它可以’T打开。同样的事情如果它’关闭并关闭,但定时器HASN’T已设置。在这些情况下,我们打印一条消息并返回true。

现在它’s time for an after routine. If ##SwitchOn wasn’t stopped in the before routine, and the ##SwitchOn action routine didn’看到玩家应该应该的任何原因’被允许切换烤箱,我们将开始烤箱’s daemon using the StartDaemon() routine.

A daemon is a routine attached to an object using the daemon property. It can be started with StartDaemon(object)and stopped with StopDaemon(object). By starting a daemon, you indicate that you want it to be run at the end of each turn until you stop it again. It will run regardless if the player is near the object or not. In this case, we use a daemon to heat food. Even if we had other rooms the player could explore, and the player left the kitchen, the oven should keep heating any food that’在它中,只要烤箱’s timer is set for.

Back to the after routine. In line 106, we react to ##SwitchOff by stopping the oven’s daemon.

Then we react to ##Open. If the player opens the oven when it’S ON,我们关闭烤箱,停止守护进程并打印合适的信息。由于我们也返回true,默认消息赢了’t be printed.

微波炉,继续

PunyInform代码第6部分

如果玩家检查烤箱,我们会说’s clean and tidy, and then we have them examine the timer using <>; The double angle brackets mean “执行此操作,然后返回true”.

然后是’s the daemon. It’负责加热食物的负责,以及当定时器达到零时关闭烤箱。

如果意大利面位于烤箱中,请通过四个步骤提高意大利面的温度。我们通过调用自定义例程来完成此操作个人财产 of the Spaghetti object, named change_temperature. We could have named this property pretty much anything we like, but what is does is change the temperature of the spaghetti, so change_temperature seemed appropriate.

图书馆提供的属性全部共同特性 . You can add a few common properties yourself using the syntax Property my_property; but the number of common properties is limited, especially when using the z3 format. You can however use any number of individual properties. You do so by just writing the name you want to use in an object declaration, and the value it should have for that object. Individual properties take up a little more space and are a little slower to access than common properties, but for many uses that’s not so important.

Then we decrease the timer setting by 1, using Timer.setting--; . This is equivalent to writing Timer.setting = Timer.setting - 1; . There is also ++ to increase a variable by one.

现在我们检查计时器是否已达到零。如果有的话,我们还仔细检查烤箱仍然在,如果是我们这样做:

  • 关闭烤箱
  • Set waittime_waiting to false. This is a signal to the ext_waittime extension that if the player is currently waiting because they typed something like “wait until 8:30” or “wait for 20 minutes”,现在应该中止等待– the player wouldn’当食物再次变冷时,不想继续等待。
  • 打印一条消息,说烤箱会发出ping并关闭。

最后,我们检查烤箱现在是否已关闭,如果它也停止守护程序。

In line 132, we define a property called add_to_scope. . The add_to_scope. property is used to say “每当该对象处于范围(播放器可以参考)时,也会在范围内放置一些其他对象。” It can hold either a list of objects to place in scope, or a routine which places objects in scope using PlaceInScope(object);. In this case, we just need to place a single object in scope, and there are no ifs or buts about it, so a list is fine. The list can hold up to four objects in a z3 game, or up to 32 objects in a z5 or z8 game.

So, why do we need add_to_scope. here? Normally, we could attach the timer to the oven by making the timer a child object of the oven (put it “in”烤箱),但这会变得令人困惑,因为烤箱也是一个容器,所以孩子们都认为是inside烤箱。这是一个案例add_to_scope.派上用场。另一个例子可以是电话。当你’再次与电话交谈,那个人应该处于范围,即使他们’没有你在房间里。为实现这种效果,只要呼叫持续,您就可以将该人添加到范围内。

意大利细面条, part one

PunyInform代码第7部分

意大利面的板是另一个复杂的物体。代码在此处分为两个图像。

We have given it an individual property called temperature. This starts out as 0, meaning room temperature. We have decided that 29 is the maximum temperature, and this is the temperature it gets if we warm it in the microwave oven for a long time. 29 probably corresponds to about 200° C.

然后是’s another individual property called change_temperature和it holds a routine which does this. The routine is meant to be called with one argument (deg), and it tries to change the temperature that much, while making sure the temperature stays in the range 0 to 29 inclusive.

And we have another individual property called print_temperature, holding a routine which does just this. It uses a switch statement which is a convenient way of doing different things depending on the value of an expression. You could achieve exactly the same effect with a series of if + else statements, but this may be more readable.

Keep in mind that Inform only has integer arithmetics, so self.temperature / 6 will be rounded down to the neareast integer. If you wanted to know the remainder of the division, you would use %, as in self.temperature % 6 .

意大利细面条’除了意大利面,否则守护守护进程只有一份工作:让意大利面条冷却一步一步 ’S的温度已经在0.注意,此守护程序始终运行,因此当在烤箱中加热意大利面时,其温度由烤箱增加四个’每次转弯,守护守护程序并由自己的守护进程减少。添加到烤箱中的每个转弯时,温度增加3。

意大利细面条, continued

PunyInform代码第8部分

意大利细面条 has an invent property. This is used to affect how the object is printed when PunyInform lists objects, like when taking inventory, when looking inside something else (“search oven”), or when printing the objects in a room. The invent routine is called twice:

  • First invent is called with inventory_stage 放 to 1. This happens just as the object name is about to be printed. If the invent routine returns true, nothing further is printed (and invent isn’t called again).
  • Then invent is called with inventory_stage 放 to 2 when the object name has been printed but additional information like ” (providing light)” hasn’t. If the invent routine returns true, nothing further is printed.

对于意大利面,我们用这可以说意大利面是多么温暖,除非我们可以’T触摸意大利面,只有在它时发生的’s in the oven. ObjectIsUntouchable(object, dont_print) is a routine provided by PunyInform to decide if an object can’因为那里而被球员感动’在途中是一个障碍。如果我们不’t give a value for the dont_print parameter, or we give it the value false, a message will be printed if the player can’触摸对象。我们不’t want that here, so we give it the value true.

然后是’s the description property. Since we want to print some words descibing the temperature of the spaghetti both in the invent和the description routines, it makes sense to put the code to print those words in a routine of its own. Hence the print_temperature property.

计时器

PunyInform代码第9部分

这是烤箱的计时器。它’s not in located in a room, but is dragged into scope by the oven. The timer has an individual property 放ting which holds the number of minutes it has left to go.

The description property tells the player the current setting of the timer.

We use the before routine for multiple purposes:

  • 如果他们试图拿起计时器,我们会给玩家一个明智的消息。
  • 如果玩家试图转动,推动或​​拉动计时器(这一切都被视为相当合理的尝试设置它),我们可以帮助他们使用它们需要设置计时器的语法。
  • 如果玩家试图打开定时器而不是烤箱,我们将动作重定向到烤箱。我们在烤箱对象中有一堆代码来处理交换机,所有这些都将应用,就像播放器所键入的那样“switch on the oven”。请注意,我们使用双角括号语法来执行操作,这意味着我们之后还返回真实,从而阻止了对计时器的交换机动作的默认响应。
  • We allow the player to set the timer to a number (of minutes). When a grammar line allows the player to type a number as part of the input, that number is kept in parsed_number.

街道和初始化的例程

PunyInform代码第10部分

The final object in the game is the Street location. As soon as we get out here, a ##Look action will automatically be performed. We use the after routine to react to this by ending the game and printing a message.

In the Initialise routine, we need to set the time of day, since this is a game that shows the time on the statusline. We set it by calling SetTime(time, step); . time is the number of minutes past midnight, so 20 * 60 means 8:00 PM. step is the relation between minutes and moves. A value of 1 means that one move takes one minute. A value of 5 would mean that one move takes five minutes. A value of -5 would mean that five moves take one minute.

然后我们开始意大利面’S守护程序,然后将为整个游戏运行。我们打印了对游戏的介绍。

Links

Fredrik Ramsberg.

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

发表评论

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