雷神之锤Ⅱ
Quake 2

佚名

另有一篇候毅的攻略,点此
另有一篇《生存还是死亡--Quake I、II 连线经验》,点此

作《雷神》的主人
--QUAKEC强力教程(版本3.4)


  ——QUAKEC的语法和一些实际应用的经验。
  QUAKEC说明文件和其他所有的软件规范一样,都是经过了一个个版本 的不断改进和演变的。到现在已经是3.4版了,并且还在不断地更新。到 本文发布的时候为止,已经有消息说4.0版已经要出来了。有意思的是, 对QUKAEC的改进贡献最大的并不是来自id Software,而是一些超级发烧 友的义务劳动。这还有另外一层特别的意义。在我得到的大多数关于 QUAKEC的文档里往往都有大意如下的一段话:此文档是按照我们自己对于 《QUAKE》文件结构的理解来编写的,我们无法保证在这里所有的一切都 是正确的。我们不对因此而引起的一切后果负责,别说我没警告过你! 怎么样?是不是挺吓人的?但既然他们都这么说,我也就只好也先给 大家打个招呼了。不过大家放心,我在这里所介绍的,都是笔者自己动手 实践过的。没有试过的……至少我会给大家打声招呼。好了,不多说废话 了,我们一起来进入QUAKEC的世界吧!
  首先我们要有一些准备工作。因为要想熟练地用QUAKEC,就必须要知 道一些关于3D建模方面的知识。另外还要注意,QUAKEC只能用于已经注册 过的版本上。最后——当然您要能懂得一点C语言的基本知识。
  下面是一些专用字的说明:
  0xABCD : 十六进制数
  char : 8位有符号整数
  u_char : 8位无符号整数(字节)
  short : 16位有符号整数
  u_short : 16位无符号整数
  long : 32位有符号整数
  u_long : 32位无符号整数
  float: 32位单精度实数(浮点)
  
  第一讲 QUAKE的地图
  谈到QUAKE的地图编辑,内容实在是太多了。笔者在这里显然不可能 介绍得很全面(其实QUAKE的地图编辑本身就可以开一个讲座了),这里 涉及的都是一些和QUAKEC有关的部分。至少,你辛辛苦苦做出来的地图 还是要通过QUKAEC来加到游戏里去啊。
  一、关于地图的一些基本信息
  1、坐标系统
  《QUAKE》中使用了标准的“左手系”坐标,如图所表示。“左手 ”的意思是指你把左手半握拳,大拇指树起来的话,大拇指就表示了Z 轴,其余四个手指是从X轴指向Y轴。
  有一些物体当然是摆放得比较随意,比较斜一点,这时就要用到 一个“角度”的概念了。《QUAKE》中的角度是如下设定的:
  0-359: 普通角度
  -1: 上
  -2: 下
  2、刷子(Brush)
  刷子是《QUAKE》的地图中两个最重要的概念之一。每一个刷子都 定义了一个单独的区域。每一个区域都被看成是四个以上相互交叉的 面形成的。而每一个面又是由不在同一直线上的三个点定义的。注意 的是这三个点必须是按照顺时针的顺序排列。不过笔者至今没有弄清 楚为什么这些老外要把它叫做“BRUSH”。每一个刷子的声明 (Statement。注意!我们开始涉及到C语言的概念了!)都应是如下 形式:
  {
  ( 128 0 0 ) ( 128 1 0 ) ( 128 0 1 ) GROUND1_6 0 0 0 1.0 1.0
  ( 256 0 0 ) ( 256 0 1 ) ( 256 1 0 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 128 0 ) ( 0 128 1 ) ( 1 128 0 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 384 0 ) ( 1 384 0 ) ( 0 384 1 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 0 64 ) ( 1 0 64 ) ( 0 1 64 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 0 128 ) ( 0 1 128 ) ( 1 0 128 ) GROUND1_6 0 0 0 1.0 1.0
  }
  也许您第一次看到它们的时候会觉得有些脑子发晕,反正我是。其 实这一大堆东西就是定义了一个从点(128,128,64)到点(256,384, 268)的长方体。每一行的意思如下:
  128 0 0
  128 1 0
  128 0 1
  GROUND1_6
  0
  0
  0
  1.0
  1.0
  第一点
  第二点
  第三点
  材质
  x_off
  y_off
  旋转角度
  X轴范围
  Y轴范围
  解释:
  第一点、第二点和第三点:这三点定义了一个面,所以当然不能是 在同一条直线上。每一个面只能被定义一次。
  材质:所使用MIP材质的名字(MIP将会在以后讲到)
  x_off:材质的X轴偏移,必须是16的倍数
  y_off:材质的Y轴偏移,同样必须是16的倍数
  旋转角度:材质旋转的角度,单位是度。
  X轴范围:材质在X轴方向上的长度范围
  Y轴范围:材质在Y轴方向上的长度范围
  3、*.MAP文件基础知识
  其实MAP文件的结构挺简单的,它就是一个文本文件。所有的 《QUAKE》编辑器都应该同时支持UNIX和DOS两种文本格式。
  MAP文件是对《QUAKE》的关卡建造格式的说明。建议在改动 时尽量修改MAP文件,因为所有的id Software发布的工具都是针 对MAP文件做改动的。注意其实MAP文件都是一组“未编译”的数 据,只有在它转换为*.BSP文件之后才可以被《QUAKE》所认识。 转换是用专门的BSP转换工具来完成的,比如QBSP.exe。另外,MAP 文件还要由专门的光影处理器处理过,这样《QUAKE》才能计算出 在某个地方的光线强度。否则的话在游戏中会以最强光线显示这 部分地图。最后,为了使此地图在游戏中运行时速度更快和不出 错,还要用VIS这样的工具进行处理。总之,《QUAKE》总的地图 设计是一件非常费时间的事,比当年设计《DOOM》的地图要复杂 得多,即使你现在用的机器比那时候快了很多,但是可能你花费 的时间会更多。
  MAP文件通常的结构如下:
  
  {
  entity
  {
  brush (optional)
  }
  }
  ...
  
  在MAP文件中可以加进注释,方法和C++中是一样的,用“//” 表示后面是注释的内容。
  
  在MAP文件中可以使用很多种实体(entity)和刷子的组合。
  但是所有的MAP文件都要有一个worldspawn的实体,它通常都是
  文件的第一个入口,里面定义了所有这个关卡中常用的刷子。每
  一个MAP文件中只能有一个worldspawn实体。其构造如下:
  "classname""worldspawn" // 表示这是建造本关卡的QUAKEC函数开始!
  "wad""DIRPATH" // 表示使用哪一个图形文件,即*.WAD文件
  "message""TITLE" // 本关的名字
  "worldtype""#" // 本关的类型,0表示为中世纪的,1表示古巴比伦式
  (这是基本模式), 2表示金属
  "sounds" "#"// 决定放哪一首CD音轨
  下面是一个简单的MAP文件示例:
  {
  "sounds" "1"
  "classname""worldspawn"
  "wad""/gfx/base.wad"
  "worldtype""0"
  {
  ( 128 0 0 ) ( 128 1 0 ) ( 128 0 1 ) GROUND1_6 0 0 0 1.0 1.0
  ( 256 0 0 ) ( 256 0 1 ) ( 256 1 0 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 128 0 ) ( 0 128 1 ) ( 1 128 0 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 384 0 ) ( 1 384 0 ) ( 0 384 1 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 0 64 ) ( 1 0 64 ) ( 0 1 64 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 0 128 ) ( 0 1 128 ) ( 1 0 128 ) GROUND1_6 0 0 0 1.0 1.0
  }
  }
  {
  "classname" "info_player_start"
  "origin" "256 384 160"
  }
  你可以看到,所有的刷子都包括在实物里了。其实MAP文件中 最复杂的部分是在于实物,这也是我们下面要进一步讨论的。
  二、实物(entity)的基本知识
  1、基本结构
  实物是在MAP文件中另外一个重要的组成部分。实物当然可以
  理解为一个东西,但是不完全是。有时它是一个触发的机关,有时
  它是活动的暗门。一个实物的结构通常如下:
  {
  "classname" "light"
  "origin" "0 128 64"
  "light" "255"
  }
  这就是普通的实物结构的声明。“普通”的意思是说它还没有
  和刷子结构联系起来。当两者联系起来之后的声明形式如下:
  {
  "classname" "func_door"
  "angle" "0"
  "speed" "16"
  "targetname" "t1"
  "sounds" "1"
  "wait" "16"
  { 
  ( 128 0 0 ) ( 128 1 0 ) ( 128 0 1 ) GROUND1_6 0 0 0 1.0 1.0
  ( 256 0 0 ) ( 256 0 1 ) ( 256 1 0 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 128 0 ) ( 0 128 1 ) ( 1 128 0 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 384 0 ) ( 1 384 0 ) ( 0 384 1 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 0 64 ) ( 1 0 64 ) ( 0 1 64 ) GROUND1_6 0 0 0 1.0 1.0
  ( 0 0 128 ) ( 0 1 128 ) ( 1 0 128 ) GROUND1_6 0 0 0 1.0 1.0
  }
  }
  注意,和实物相结合的刷子有一个“原始”标签,它是用来对在关 卡中的位置作一些偏移。
  在接下来的部分中,我将给大家介绍一下实物的结构及其中的各个 选项。各个入口(entry)其实可以按任意次序排列,另外还有很多的 可选项。
  2、spawnflag标签
  spawnflag标签是一个附加的标签,就是说即使一个实体中已经有了
  一个原始标签后也可以再加上一个SPAWNFLAG标签。它是用来说明一些额
  外的属性:
  1 - 额外的生命或弹药(比如生命超过100等)
  2 - 超高生命
  256 - 表示普通难度以上
  512 - 困难难度以上
  1792 - 这个值仅仅在死亡模式中才使用。
  3、实物的语法
  在《QUAKE》中,实物(entity)可以定义怪兽、物品, 另外还可以定义即将发生某种事件的位置。它们其实和DOOM 中的THINGS和LINEDEF这两种类型相对应。
  实物的定义当中包括了一系列的项目:此实物是什么东 西,它什么时候出现,在什么位置出现等。每一条项目的后
  面都跟有一些对它各方面的详细规定。每一个实物的定义都
  有一个“类名(class name),类名就是在QUAKEC中的函数
  名,它与“代码堆(code lump)”有很密切的关系。在对它
  们作出说明的时候,我用到了“特性(specfics)”和“内
  容”这两个词,也许他们并不是很确切,不过id并没有规定
  他们叫什么,而且国外的玩家在说明他们的时候用的两个单
  词也不是很容易恰当地翻译过来,就用他们吧!
  特 性 内 容 说 明
  "classname" "name" // 定义实物的类型,是必须要求的选项
  "origin" "X Y Z" // 定义其在空间中开始放置的位置坐标
  "angle" "#" // 此实物面对的方向或是移动的方向,有时用角度来表示
  "light" "#" // 这是在光影类名中要使用的数值
  "target" "t#" // 对应一个目标名
  "targetname" "t#" // 就象是DOOM中的linedef标签
  "killtarget" "#" // 当此角色击中你的时候带给你的伤害力
  "spawnflags" "#" // 用来说明一个非缺省的实物
  "style" "#" // 同上,是用来说明一个非缺省的实物
  "message" "string" // 当事件被触发的时候显示的信息,用/n表示信息结束
  "mangle" "X Y Z" // 指出中断镜头的视角
  {BRUSH INFO} // 这是在描述触发事件、门或是平台等的实物中加进的刷子,它
  用一对括号圈起来
  下面是仅在描述游戏中的怪物角色的实物使用的特性:
  "speed" "#" // 此角色的移动速度
  "wait" "#" // 在反复移动间的停顿时间,用秒或十分之几表示
  "lip" "#" // 此特性和调整角色的开始位置有关
  "dmg" "#" // 表示当此角色击中你的时候带来的伤害力
  "health" "#" // 在此角色在被触发以前的伤害力
  "delay" "#" // 事件触发以前的时间
  "sounds" "#" // 此角色的声音
  "wad" "wadfile" // 此关卡中的材质使用的wad2图象文件
  "height" "#" // 一个平台可以上升的高度
  实际使用中的结构如下:
  {
  "specific1" "arg1" // 第一个特性,通常就是类名
  "specific2" "arg2" // 第二个
  ... // 其它特性...
  {
  <INSERT BRUSH INFO HERE> // 这部分是对于描述门、触发器或是平台的实物中加 进的刷子
  }
  }
  在最后《QUAKE》中使用的*.bsp文件中的怪物数目取决
  于一个叫model structure(角色结构)的结构中的数目,而
  这个数目又来自原始的*.map文件中定义的数目。worldspawn
  模块则定义了整个关卡的内容。
  《QUAKE》中的怪物角色是定义在一个长方体中的,这个
  长方体用两个对角点的坐标定义。因此可以想象,《QUAKE》
  中的角色是始终和地面平行的。不过如果这么推理的话如果
  角色出现在一个斜坡上就有些不合理了……
  4、全部实物列表(对《QUAKE》1.01版)
  air_bubbles : 上升的气泡
  ambient_drip : 滴水的声音
  ambient_drone : 机器的声音
  ambient_comp_hum : 电脑的背景声效
  ambient_swamp1 : 青蛙的呱呱声
  ambient_swamp2 : 这种声效和上面的青蛙叫声很接近
  event_lightning : 雷电机关,用来杀死Cthon的。Cthon就是在共享版最后
  一关那个打不死的老王
  func_door : 门
  func_door_secret : 这是一种通过触发来打开的门
  func_wall : ……一堵可以移动的墙?
  func_button : 一个按钮
  func_train : 平台,但是是那种会沿着固定的轨道移动的平台
  func_plat : 升降机
  func_dm_only : 这是一种只在deathmatch中出现的升降机
  info_null : 这——什么都不是
  info_intermission : 一种静止的镜头
  info_player_start : 主玩家扮演的角色出现的位置,只能有一个。主玩家就
  是在联网中建立新游戏的那个
  info_player_deathmatch : 开始一个死亡模式,这个实物可以有多个
  info_player_coop : 开始一个合作模式,它也可以有多个
  info_player_start2 : ? 开始另外一个游戏?
  info_teleport_destination : 给角色一个传送的目的地
  所有的项目都有一个目标标签(target tag)。当目标标签被碰到后将触发某个特定事件。
  item_cells : 雷电枪的弹药
  item_rockets : 箭炮和榴弹的弹药
  item_shells : 钉枪和超级射钉枪的弹药
  item_spikes : 步枪和双筒猎枪的弹药
  item_health : 救护包
  item_artifact_envirosuit : 生化防护衣
  item_artifact_super_damage :四倍攻击力
  item_artifact_invulnerability : 无限防护力
  item_artifact_invisibility : 隐形戒指
  item_armorInv : 红色装甲
  item_armor2 : 黄色装甲
  item_armor1 : 绿色装甲
  item_key1 : 银色装甲
  item_key2 : 金钥匙
  item_sigil : 过关符号
  light : 预设的光线,但是没有可见的光源。
  light_torch_small_walltorch : 墙上的小火炬
  light_flame_large_yellow : 黄色的大火焰
  light_flame_small_yellow : 黄色小火焰
  light_flame_small_white : 白色小火焰
  light_fluoro : 荧光灯,发出嗡嗡声
  light_fluorospark : 荧光灯,发出滋滋声
  monster_army : 鱼
  monster_dog : 猎狗
  monster_ogre : 手拿炸弹的胖子
  monster_knight : 武士
  monster_zombie : 腐尸
  monster_wizard : 巫师
  monster_demon1 : 魔鬼
  monster_shambler : Shambler
  monster_boss : Cthon,共享版中的老王
  misc_fireball : 小火球
  misc_explobox : 炸药包
  path_corner : 用来定义轨道平台的路径
  trap_spikeshooter : 发射钉子的机关
  trap_shooter : 这是一种不用触发就一直向外发射钉子的机关
  trigger_teleport : 升降机,由walkover的值触发
  trigger_changelevel : 改变关卡
  trigger_setskill : 改变难度
  trigger_counter : 在被触发到指定的次数以后激发某个事件
  trigger_once : 只能使用一次的触发事件(比如打开一道门)
  trigger_multiple : 可重复触发的触发事件(比如说升降机的升降)
  trigger_onlyregistered : 仅仅在已经注册的版本中触发
  trigger_secret : 触发一个事件并且得到额外的奖励
  trigger_monsterjump : 使目标怪物向上跳(?)
  trigger_relay : 允许一次触发引起多个动作(或引起某个延迟的动作)
  trigger_push : 把玩家往某个方向推动(比如在通风道中)
  weapon_supershotgun : 超级射钉枪
  weapon_nailgun : 步枪
  weapon_supernailgun : 双筒猎枪
  weapon_grenadelauncher : 榴弹
  weapon_rocketlauncher : 火箭发射器
  weapon_lightning : 雷电枪
  写到这里的时候,可能朋友们看着会说:“你说了这么大一堆, 我还是不知道怎么用,怎么编写QUAKEC的程序……”,那么请大家 别急,在以后的介绍中我会用实际使用中的例子来给大家看的。前 面的路还很长,但千万不要泄气,笔者在自己设计的关卡中和朋友 战斗时的感觉就象是在守护自己辛辛苦苦建立起来的家园一样,心 情绝对神圣!而且QUAKEC的力量那样强大,不仅仅是可以改动地图、 人物、武器、连整个游戏的基本玩法都可以改变——你踢过 《QUAKEC》中的足球吗……
  QUAKEC的语法
  本教程又和大家见面了!上期的教程出了之后,得到了一些《QUAKE》玩家的意 见,另外自己也反省了一下,看来是有了一个误区:就是我还没有把最基本的语法、 专用名词等说明就想直接给大家介绍在实际设计中的应用了。其实我的本意是想 QUAKEC中的语法和C相差不多,有区别的地方就直接在用到的时候再提一下就行了。 但是看来这样做的条理性比较差,而且不少玩家抱怨说本来对C就不熟或根本就没 学过……好吧,我投降!笔者还是决定从这期开始,尽量简洁明了地把有关 QUAKEC语言的基本语法给大家作一个介绍。不过那样的话,篇幅就比原来预料的 更长了,实难洗脱混稿费之嫌……
  一、注释、名称和类型
  注释:
  和C++中的注释方式一样,有下面两种形式:
  // 后面跟注释内容,直到下一行开始
  或
  /*注释块*/
  名称:
  在QUAKEC中的各种变量、函数或域等的名称必须满足以下条件: 最多由64个字母组成,开始第一个字母必须是A-Z、a-z或_,后面可以 跟0-9的数字。
  新类型的定义:
  关于这个问题要告诉大家一个坏消息:在QUAKEC中是不允许你自己定 义新的类型的。比如说你不能定义一个叫ammo的浮点变量,这个名字是专 用的,它就是用来表示弹药的。
  结构和对象的定义:
  在C或C++中定义一个结构或对象是很方便的,他们用来在一个结构中 放置一组相互有关联的信息。比如,你可以用一个结构来存放玩家所有武 器的弹药,因为显然它们是有着明显联系的。
  但是要注意的是,虽然实物(entity)和矢量(vector)很明显都属 于结构这一类,但是在QUAKEC中不允许自行建立新的实物和矢量。不过你 可以按自己的一些要求对现有的实物类型进行修改。
  二、常量和变量
  变量的定义:
  通常对于变量的定义采用如下形式:
  类型 变量1,变量2;
  其中“类型”是在QUAKEC中已经规定的变量中的一种。
  变量范围
  共有两种变量范围。缺省情况下所有的变量都是“全局(global)” 型的,它们可以被别的函数访问,并且由所有的函数共同享有(当然包括 了给予访问权的所有网络客户)。
  另外一种变量范围是“局部(local)型”,定义方法是在函数内部 用“local”关键字在变量类型前进行定义,这种变量仅仅在函数内部可 见(注意它们将被分配到堆栈里)。
  另外函数的参数也是被当作局部变量来看待的,它们仅在函数内部 可见,但它们的值可以改变。
  常量的定义:
  对于一个全局变量,如果初始化时给它赋了一个值,则将被当作一个常量。 常量定义的通常方式为:
  类型 变量1 = 值;
  注意,虽然看起来这象是一个变量的定义,但是当我们在这个变量初 始化的时候赋一个初值,则它的意义就完全改变了。常量没有象变量那样 有一个专门的内存地址进行存放,而且它们在游戏存盘的时候也不会写进 存盘文件里去(只有通常的变量才写进去)。
  在赋了常量的初值后,就不能再进行改动了,如果你一定想给常量一 个新的值……这就是故障发生的原因!
  三、 操作符
  逻辑操作符:
  ! // 逻辑非
  && // 逻辑与
  || // 逻辑或
  这里需要注意一点,在if()中的条件表达式里往往有着两个或更多的逻辑 判断句。在这种情况下,所有的逻辑判断式都要先于条件判定之前就得出 结果(和BASIC中的习惯一样,而不是C中的习惯!)
  比较操作符:
  <= < >= >
  == // 等于
  != // 不等于,这两个符号都和C中一样
  浮点数和整数运算操作符:
  * / - +
  下面两个运算符是对于整数的二进制位:
  & // 位与
  | // 位或
  它们同样也可以运用与浮点数的运算,所以使用这两个运算符的时候往往 都带有一些“位”的因素在里面。
  四、函数的定义
  普通函数
  通常一个函数的定义结构如下:
  type (type param1, typeparam2, ... ) function =
  {
  ... code ...
  return expression;
  };
  说明:
  1、在每一行的最后一定有一个“;”号。
  2、函数返回表达式可以有多个,并且可以放在函数的任意位置。
  3、如果返回值为空(void),则返回表达式可以省略。
  下面是几个例子:
  void () think = {...};
  entity () FindTarget = {...};
  void(vector destination, float speed, void() callback) SUB_CalcMove = {...};
  调用函数:
  在QUAKEC中调用函数的方式如下:
  函数名( 参数1,参数2,... )
  注意参数最多为8个。
  函数声明:
  如果你想在定义一个函数之前就使用它,则必须首先进行声明,否则 QUAKEC的编译程序无法使用这个函数。
  下面是声明一个函数的形式:
  type (type param1, typeparam2, ... ) function;
  桢函数(frame function)的定义:
  桢函数(也叫状态函数States)是一种特殊的函数,它可以简化游戏中 各种角色模型运动时桢的定义。
  下面是一个例子:
  void() framename = [$framenum, nextthink] { ...code...};
  上面这个定义等同于下面的函数定义:
  void() framename =
  {
  self.frame= $framenum; // the model frame to displayed
  self.nextthink = time + 0.1; // next frame happens in 1/10 of second
  self.think = nextthink; // the function to call at the next frame
  ...code...
  };
  五、循环和条件
  循环结构:
  1、
  if( expression )
  {
  statements
  }
  else
  {
  statements
  }
  2、
  while( expression )
  {
  statements
  }
  或
  do
  {
  statements
  }while( expression )

  QUAKE-C 中的基本类型
  一、简单类型
  1、空(void)
  这是一个“空”的结果,主要是用在函数的定义中(比如一个不返回
  值的函数)
  2、浮点
  浮点当然就是表示一个小数点浮动的值,不过布尔变量(TRUE和FALSE)
  也是用浮点方式存储的,浮点中其实还包括了整数和位标志。
  有效的表达式: 12 1.6 0.5 100
  无效的表达式: .5
  注意在QUAKEC中空格是非常重要的,比如“a-5”这个表达式在QUAKEC
  中会出错,因为程序首先把表达式处理成“a”,然后是“-5”,所以
  它就不认识了。正确的写法是“a - 5"。
  3、矢量
  一个矢量由三个浮点坐标构成。它用来表示位置或是在3D空间中的
  方向。有效的表达式是:‘0 0 0’或‘20.5 -10 0.00001’
  矢量一定是用单引号括起来,不要用双引号,你用的话程序并不会
  说你出错,仍然可以进行下去,但是双引号里的内容都将被认为是字符
  串。在定义了一个矢量vector1后,此矢量的x、y和z轴坐标分别可用
  vector1_x、vector1_y和vector1_z来表示。
  4、字符串
  字符串在QUAKEC中主要是用来表示文件名和传递给玩家的一些信息。
  比如:: "maps/jrwiz1.bsp" 或"ouch!\n" ,用 \n 表示换行。字符串
  不能象变量那样在程序中进行修改或是把两个字符串连起来(在C中是
  可以的),因为它们是用固定的内存地址存放的。
  5、实体(entity)
  实体是指游戏中的所有物品、玩家和怪物。他是一个结构,由不同
  的部分组成。
  二、域
  1、域的定义
  与其他的类型相反,实体是由许多部分组成的。每一个部分都有自 己的名字和类型,以把自己和实体中的其他部分区别开来。每一个部分 就叫一个域。有些域并不表示一个确定的值,它们用来存放在特定条件 下执行的某个函数。
  2、建立新的域
  在实体已有类型上进行扩展只有一种方法,就是在实体结构的最后 加上新的域。只要定义一个新的域就行了。
  .类型 域名;
  比如,你想在游戏中加进去一种抛石器,则肯定要为游戏中每一位 玩家都设立一个存储石块的域,比如在代码中加进下面这句话:
  .float ammo_sling;
  这样游戏中的每一个相关的实体都将具有一个叫ammo_sling的域,特别 是表示玩家的实体。
  下面是所有可能新定义的实体域及其类型:
  .float field_name;
  .string field_name;
  .vector field_name;
  .entity field_name;
  另外你并不需要专门把这些定义一起放到一个特定的地方,你可以把它 们放到源代码中的任何位置。
  3、对类型作的改动
  QUAKEC的编译器工作时读的第一个文件是defs.qc,它里面有许多实体 和域的定义。这些定义是极其严格的,所以我们最好不要去动这个文件。
  三、QUAKEC的角色(model)定义
  使用QUAKEC的代码我们不仅可以定义实体的行为,还可以定义游戏 中角色(model)的各种动作和行为。游戏中的角色包括了怪物、玩家 和一些特殊的运动的东西,角色的数据文件是*.mdl。 角色的各种属性在表示时都要在句子的最前面加上一个“$”符号。 它们不能放在函数定义的内部。有些句子连QUAKEC的编译器都不能直接 解释,但是它们对于角色产生器工作时很有帮助。
  角色的名字:
  $modelname name
  其中“name”就是实体中定义的模型文件的名字,比如:
  $name armor
  directory
  $cd dir
  这句话说明了你的模型文件(model file)存放的位置,比如:
  $cd /evil/models/armor.
  特殊的动画标签:
  $flags flag_value
  注意QUAKEC并不对这个域解释,但是它对建立角色模型的程序很有帮助。
  未完待续……
高晶 □ 葵花宝典 □ 来自网上的攻略