				基础 LPC
        	          作者: Descartes of Borg
                	  第一版: 23 april 1993
	                  第二版: 16 june 1993

第二章: LPC 程式

2.1 关于程式

这一章的名字取得不怎么好, 因为没有人用 LPC  写程式. 写 LPC  程式的人写
的是物件 (objects). 这两种说法有啥差别 ?  好吧, 就我们现在的目标来说,
差别在于两者档案执行的方式不同. 当你“跑”一个程式的时候, 都是从程式中
固定的地方开始执行. 换句话说, 就是所有的程式开始执行的时候, 一定有个地
方写清楚要从那里开始. 另外, 程式有一个固定的终止点, 所以执行程式只要执
行到该终止点, 程式就中止执行. 总之, 程式从固定的开头跑到固定的结尾.
LPC 物件就不是这么一回事.

在 mud  里面, LPC 物件只是游戏 (driver) C 程式中, 显而易见的部分. 换句
话说, mud 程式在 driver 里面开始与结束执行. 但是实际上, 对于创造你玩的
mud 世界来说, driver 并没有做多少事. 反之, driver 相当依赖 LPC  码, 并
需要执行物件中的程式码. 所以  LPC 物件不需要有起始点, 也不需要有固定的
终止点.

就像其他的程式语言, LPC “程式”可以由一个或一个以上的档案组成. 很简单,
程式要先载入 driver 的记忆体. driver  会根据本手册所教的结构, 读取物件
中一行行的程式. 有一件重要的事你要先搞清楚, 就是 LPC  物件执行时没有开
头也没有终止.

2.2 diiver-mudlib 之间的互动

我先前提过, driver  是在主机上执行的 C  程式. 它让你连上游戏, 并执行
LPC 码. 注意, 这是 mud  程式设计的一个理论而已, 也不需要比其他的方法好.
整个 mud  游戏可以全部用 C  来写. 这样游戏的执行速度快上很多, 却让 mud
缺乏可塑性, 使巫师在游戏正在执行的时候无法加入新东西. DikuMUD 就是全部
用 C  写成的. 相反的, LPMUD 的理论就是 driver 不该决定游戏内容, 而游戏
内容应该决定于游戏中的个别事物, 并能够在游戏执行时加上东西. 这就是为什
么 LPMUD  使用 LPC  程式语言. 它能让你用 LPC  定义游戏内容, 交给 driver
依需要读取并执行. 况且学 LPC  要比 C  容易得多, 这样让更多人能加入创造
世界的过程.

一旦你用 LPC  写了一个档案 (假设是用正确的 LPC),  它只是躺在你主机的硬
碟里不动, 直到游戏中有东西参考 (reference)  它. 当游戏中有东西终于参考
到它时, 这个档案就会被复制一份到记忆体里面, 并且呼叫这个物件中一个特殊
的函式 (function). 呼叫这个函式的目的是初始化 (initialize)  这个物件中
的变数. 现在, 别管你脑袋里才看到的上两句话, 因为一个对程式设计完全陌生
的人来说, 哪里会知道函式或变数到底是啥东西. 现在重要的是要知道 driver
读取主机硬碟里面的物件档案, 复制一份之后扔进记忆体储存 (既然是复本, 也
就可以有许多不同的版本 ). 你稍后会知道什么是函式、什么是变数, 并搞清楚
到底游戏中的一些东西是怎么参考你的物件的.

2.3 将一个物件载入记忆体

虽然一个物件里面并没有规定要从一个固定的地方开始执行程式, driver  却要
先找到一个固定的地方并执行之, 才能初始化一个物件. 在精简模式的 driver 
上, 这是一个叫作 reset()  的函式. 在原始模式 mud  中, 则是 create().

LPC 物件是由变数 (variable) 所组成的 (会更改的值) 而函式是处理这些变数
的程式. 函式经由 LPC  语法结构来处理变数, 语法结构包括: 呼叫其他函式、
使用外部定义函式 (externally defined functions, efuns)、基本的 LPC  运
算式 (expression) 和流程控制 (flow control mechanism).

前面这些听起来乱七八糟的吧 ?  让我们从变数开始着手. 拿“等级”变数来说
吧, 等级可以随情形不同而改变它的数值, 而不同的事物也使用玩家的等级数字
作出不同的事. 举个例: 如果你是等级十九级的玩家, 则等级变数的数值就是
 19 . 如果你的 mud  是旧的 LPMud 2.4.5  系统, 等级 1  到 19 级是玩家,
 20 级以上是巫师, 则会有许多事物会询问你的等级变数值, 判断你能不能使用
巫师的动作. 基本上, 任何 LPC  物件就是一堆会随时间不同而改变的变数组成
的. 发生在物件身上的事, 都基于该物件的各个变数里头的数值. 而常常也有许
多事会更改变数.

所以无论何时, 一个 LPC  撰写的物件被其他在记忆体的物件拿来参考时, driver
就寻找这物件里面所要找的值在哪里 (但是现在还没有任何数值) . driver  找
过之后, 就呼叫物件中的 reset() 或 create() 函式  (视不同 driver 而定)
, 来设定该物件一开始的变数值. 就这样, 经由“呼叫”“函式”处理变数.

虽然绝大多数的 LPC  程式码都从 create() 或 reset()  开始执行, 此处却不
是 LPC  程式码开头的地方. 事实上, 没有这两个函式也没关系. 如果你的物件
一开始所有的值都是 NULL  (虚无) 指标 (在此, 虚无指标我们先当它是 0  吧)
, 那你就不需要 create() 或 reset()  函式. 所以, 每个物件开始执行程式码
的地方都可能完全不同.

现在让我们搞清楚这整章在讲些什么. 问题是: 一个完整的 LPC  到底是由哪些东
西组成的 ?  好, 一个 LPC  物件简单来说, 就是一个或一个以上的函式组合起来
, 处理一个以上的变数 (或是不处理变数也行) . 各个函式之间完全不用管它们
摆的先后顺序. 换句话说:

-----
void init() { add_action("smile", "smile"); }

void create() { return; }

int smile(string str) { return 0; }
-----

跟底下的一样:

-----
void create() { return; }

int smile(string str) { return 0; }

void init() { add_action("smile", "smile"); }
_____

另外有个很重要的事提醒你, 下面这个物件只有:

-----
void nonsense() {}
-----

这样也可以, 但是这种微不足道的物件, 它大概不会与你的 mud  中的其他物件
作出正确的互动关系, 因为这样的物件没有重量、看不到......以此类推.

2.4 本章总结

LPC 码没有起点或终点, 因为 LPC  码是用来创造 driver 程式使用的物件, 而
非单独的程式. LPC 物件包括一个或多个函式, 其间先后顺序毫无关系, 而这些
函式之中, 处理多个变数 (或根本没有任何变数) . LPC 物件只是躺在主机的
硬碟里面, 等着游戏中其他的物件参考它 (换言之, 它们实际上不存在) . 一
旦一个物件被参考到, 它会被载入记忆体中, 并且它所有的变数都是零. 精简模
式 mud  呼叫此物件的 reset()  而原始模式 mud  呼叫 create()  (如果此物
件有这些函式的话 ), 让这些函式来指定一些变数的初始值. 物件中的其他函式
由 driver 或游戏中其他的物件使用之, 让物件之间达到互动并处理 LPC  变数. 

reset() 和 create() 的说明:

只有原始模式的 mud 使用 create() (请见本手册的 Introduction 一章, 有关
原始模式和精简模式的介绍). 此函式仅用来初始化刚被参考的物件.

原始模式及精简模式的 mud 都使用 reset() 函式. 在精简模式 mud  中, 
reset() 有两个功能. 第一, 它用来初始化刚被参考的物件. 第二, 在精简模式
的 mud  中, reset() 用来重新设定物件. 也就是说, 让物件回到最初的状态. 
这样可以让一个房间内的怪物重生, 或把一道门关回去......以此类推. 原始模
式的 mud  只用 reset()  作第二种功能 (就跟 reset  的意思一样). 

所以在 LP 式的 mud  中有两件重要的事情让 driver 呼叫物件中的函式. 第一
件事是创造物件. 此时, driver  呼叫物件中的一个函式来初始化物件的变数值
. 在精简模式的 mud  里, 由 reset()  做此工作 (要加上 0  参数, 后面的章
节再讨论参数是啥). 原始模式的 mud  下, 由 create() 做此工作.

第二件事是把房间重新设定回某些基本的状况. 这些基本的设定可能会与一开始
的初始值不同, 也可能相同, 而你当然也不想花时间一直去重覆做某些事 (像是
重新设定一些不会更改的变数) . 精简模式的 mud  用 reset()  函式来创造和
重新设定物件. 而原始模式的 mud  用 create() 创造物件, 用 reset()  重新
设定物件. 但是精简模式也不会失去所有的变数值, 因为有个方法能区分是创造
物件还是重新设定物件. 在精简模式要重新设定, 则 driver 传入 1  或重新设
定的数字当作 reset()  的参数. 现在这个对你来说没啥意义, 但是要记住, 你
在精简模式实际上是可以把两种情形区分开来的. 另外也要记住, reset() 在创
造物件时传入的参数是 0, 而重新设定物件时传入非零值.

翻译:
	Spock of Final Frontier		98.Jan.16.
