rkjx's Blog

小窝~~~
文章 - 51,收藏 - , 评论 - 0, trackbacks - 1

2007年02月



    摘要:

修改MySQL中一个用户的密码

日期:2005-11-09  点击:462  作者:  来源:

在MySQL中修改一个用户(比如叫"hunte")的密码,可以用如下3个办法:

 

>>>
#在控制台上输入
bash$ 此处阅读全文



金点工作室制作手札


 题目: 《制作手札——RPG是怎样做成的》
 备注: 作者:汪疆
成都金点工作室的首席程序员,你可以到他们的主页了解更多的情况。
文章以程序员的标准角度分析了一个RPG游戏所包含的各个部分。作为一名设计师,你可以不懂得如何去分析,但一定要能够读懂程序员的思路,这是每一个游戏开发者应具备的基本功。

 

制作手札---RPG是怎样做成的
作者:汪疆

  自从我们的第一个正式电脑游戏《冲击》完成之后,已经有很长一段时间没有碰这方面的东西了,不过在我心中好象一直在期盼着什么东西……目睹着当今五彩缤纷的游戏世界和国产游戏的尴尬境地,我忽然有一种莫名的冲动,做游戏的冲动。也许是以前有过这方面的经验或者说是教训吧!我知道应该先让自己冷静下来,仔细的想一想我到底应该做什么类型的游戏?怎样做?我的目的又是什么呢?或许是对RPG的偏爱,或许是因为RPG实现起来相对简单而且容易发挥吧(一个好朋友的建议)!所以,我最终还是选择了它。
  好,现在就让我先来说说我的计划吧:
  1、 经过反复的思量之后,发现以我现有的条件和实力,想作出一款超越《仙剑》的RPG无疑是个天方夜谭^_^,首先就没有美工,更加谈不上剧本和音乐了!所以,何不退而求其次,把它当作是一场实战演习吧!并且记录下整个游戏的制作过程,和大家一起分享,岂不更妙!
  2、 开发平台我选择Microsoft的VC++5和DirectX SDK,这是当今的主流游戏开发平台,而且预计在相当长一段时间内都不会被淘汰。但是,在这里我不打算过多的讲解具体的程序代码,那样会浪费太多的时间,更会失去大部分的读者!还好,我们身处在一个资讯相当发达的社会中,Internet连接着你和我,想看游戏或是源程序的朋友可以来我们的主页下载(http://www.gpgame.com/)随时欢迎您的光临!(注:这里可以加上杂志的配套盘)
  3、 为了让这篇文章不至于枯燥的如同一本C++技术手册,我会尽量从游戏设计的整体规划入手,把叙述的重点放在设计思想的建立和一些技巧的应用上面,而并不局限于某种具体的编程语言。所以即使你不懂编程也一样可以轻松的读懂它,当然,如果你已经是一位程序高手的话,那就更妙了!
  4、 由于写这篇文章是和游戏的制作同步进行的,所以看上去可能会有一种读日记的感觉,不过也许只有这样的感觉,才是最真实的!
  好了,就让我们一步步的去揭开RPG的神秘面纱吧。

三月二十六日 星期五:策划并完成剧本创作

  故事是RPG的灵魂,每个成功的RPG游戏都是一个动人的故事,当我第一次打爆《仙剑》后,脑海中映像最深的也是那一段凄美的故事。经常想:如果当时李逍遥要是如此……如此……,那么就会这般……这般……(停!我怎么越扯越远呢?真是不好意思^_^)
  不过对我们来说,既然是一次练习,游戏的故事情节自然应该是简单而清晰的,这样有助于大家更好的理解游戏设计的思路,而不会被错综复杂的故事弄昏了头。经过一天的冥思苦想,终于弄出了这样一个'美丽'的故事:
  英雄救美(暂命名)〔即:《圣剑英雄传之英雄救美》〕
  "在很久很久以前,白云城的居民过着富足而安定的生活。这一天,我们故事的主人翁'小飞刀'正在城中闲逛(游手好闲?),突然传来了一个惊人的消息,十年前被剑圣击败的大魔王又再度出现了,并且还掳走了美丽的公主以此来要挟国王让出王位。这个坏消息迅速传开,全城为之哗然!
  相传大魔王生性残忍而且法力高强,当年剑圣也是凭借一把'圣剑'的威力才将其击败,剑圣死后'圣剑'也遗失在了城外的森林中,一直没有被人找到。所以大魔王才又变得如此的肆无忌惮!
  得知了这个消息后,我们的小英雄当然不会坐视不管,于是马上挺身而出,孤身一人深入虎穴找寻'圣剑',最后来到恶魔城击败大魔王救出了美丽的公主!挽救了白云城!结局是'小飞刀'当上了驸马,和公主过着幸福的生活……(是不是很老套啊!呵呵……^_^)。"

 

  故事情节敲定之后,下面要做的工作就是如何把它变成可以用程序实现的游戏剧本了。经过简单的分析,可知这个游戏一共分为了三个场景:白云城、森林 和 恶魔城,故事发展是非常简单的单线式拓补结构(可见 图1)。在游戏中一共需要三张地图来表示各个场景,具体的实现方法在后面讨论。
  游戏中出现的人物共有'小飞刀'、白云城居民、森林中的强盗、恶魔城的妖怪、大魔王和公主六类,于是我用下面的这张表就可以清楚的表示出他们之间的强弱关系:


生命值 攻击 防御
小飞刀 50 10 10
白云城居民 -- -- --
强盗 50 15 5
妖怪 100 20 20
大魔王 500 50 50
公主 -- -- --

  其中小飞刀的各项能力可通过战斗不断提升,而其他人保持不变。由此可见,要击败大魔王并不是一件容易的事,必须通过不断的战斗以提高小飞刀的能力才行。
  因为是单线式RPG,就只有两种结局。一是打败大魔王救出公主(破关结局);二是小飞刀被敌人杀死(失败告终)。
  到此为止,整个游戏的框架是不是已经比较清楚的展现在了你的脑海中,而不再是刚开始时的混乱和无从下手?如果是的话,我们今天的任务就顺利完成了,大伙累了一天可要好好休息一下了,让我们明天继续吧。(zzzZZZ………)

三月二十七日 星期六:系统分析

  "系统分析"如此专业的词汇可能会立刻吓退一大片人,我当初也是如此!不过只要你认真读完下面的文字,也许你会说一声:'系统分析'也不过如此嘛!
  顾名思义'系统分析'就是对整个游戏系统的规划,自顶向下的将它细化成一个个可由程序实现的模块;然后再把各个模块细化成一条条的语句。如此一来,写程序时就可以有条不紊,不会再像以前那样想到哪儿写到哪儿了。
  相信大家对RPG都是非常熟悉的,通常的RPG按功能可分为:消息处理系统、场景显示及行走系统、打斗系统、升级系统、对话系统和事件处理系统六大部分。其中又以消息处理系统走为核心模块,其余五部分紧紧围绕它运行。我的系统分析报告如下:

《英雄救美》系统分析记录
名称:英雄救美
类型:中文RPG
硬件要求:PENTIUM 100以上CPU、16M内存、SVGA、键盘、声卡
     (可选)。
软件平台:Windows 95/98/NT、DirextX 5.0以上
开发环境:VC++5.0、DirectX SDK
剧本:略(参见上文)
模块分析:
  一、 消息处理(核心)
  二、 场景显示及行走
  三、 打斗
  四、 升级
  五、 对话
  六、 事件处理
流程图:

(注:各个模块的具体实现略)

  在这里并没有把每个模块的具体实现方法写出来,因为我认为把大量细节上的东西一股脑的堆在面前,实在是太枯燥了。为了不让你失去耐性,我决定还是把这些东西留到具体实现的时候来讲,也许这样会较生动而利于理解一些。
  利用今天剩下的时间,我建立了两个非常重要的数据结构:'角色'和'地图'的属性类结构。

//*********角色属性结构**********
typedef struct{
char Name[32]; //角色名称
int Width,Hight; //角色大小
int x,y; //当前坐标
int old_x,old_y; //旧的坐标
int Way; //方向
int Stats; //状态
int Level; //等级
int Exp; //经验
int Lift; //生命
int MaxLift; //生命最大值
int Attack; //攻击
int Defend; //防御
int Speed; //速度
char Goods[10]; //物品(最多可带10件)
}Role_Struct;

//*********地图结构**********
typedef struct{
char Name[32]; //名字
int Width; //宽
int Hight; //高
char Ground; //地面材料
char res[7]; //保留
unsigned short *Data; //数据
}Map_Struct;

  将同一事物的属性归在一起,使程序清晰易读,有利于我们方便的管理数据、把握大局;更是顺应了当今面向对象的程序设计思路。

三月二十八日 星期天:消息处理系统

   今天的任务非常明确,就是搭起游戏的筐架(即建立游戏的消息处理系统)。
  我们的这个消息处理系统和Windows的消息处理机制其实非常相似,都是先等待消息,然后根据收到的消息转到相应的函数进行处理。所不同的是Windows 接收的消息大多是系统或是用户输入产生的,而我们的消息都是自定义的,如:小飞刀在森林中行走时碰到了强盗,那么我们就让程序产生'打斗消息'(即:Message=打斗),消息处理系统收到这个消息后就会马上转到打斗模块中去。
  不要把消息处理想的太复杂,打个简单的比方:假如你是一位接线员,在你前面的桌上有很多部电话,那么你要做的是:有电话响时就接电话,没有电话响时就什么都不做。是不是很简单!其实消息处理也就是这个道理。
  消息处理的大体框架如下:


//首先定义一些消息:
#define 行走 1 //行走消息定义为1
#define 打斗 2 //行走消息定义为2
#define 对话 3 //行走消息定义为3
#define 升级 4 //行走消息定义为4
#define 事件 5 //行走消息定义为5
#define 结束 6 //行走消息定义为6
……
//定义程序中要用到的变量
DWORD Message;//消息变量
Role_Struct Hero;//定义小飞刀的属性结构
Map_Struct Map;//定义地图的属性结构
……
WinMain() //进入程序
{
  初始化主窗口;
  初始化DirectDraw环境,并调入程序需要的图形、地图数据;

  while( 1 ) //消息循环
  {
    switch( Message )
    {
      case 行走: 行走模块();
      case 打斗: 打斗模块();
      case 对话: 对话模块();
      case 事件: 事件模块();
      case 退出: 退出游戏();
    }
  }
}

  OK!我们的程序框架已经出来了,这时你心中也一定有了一个相当清晰的轮廓吧!好了,到目前为止该游戏的整体规划也就可以告一段落了,今后几天的工作重心将转到具体模块的实现方法了。可要加油哦^_^

三月二十九日 至 四月一日:场景显示及行走系统

   如果说'消息处理'是整个程序的核心!那么'场景显示及行走系统'就是整个游戏的核心。因为作为RPG游戏,其所有事件的发生几乎都是和场景有关,例如:不同的地方会碰到不同的敌人、与不同的人对话得知不同的事情、在特定的地点才能找到宝物等等,所有的这一切都说明'场景'在一个RPG游戏中的重要地位。鉴于这部分的重要性,我们可再将它划分为:背景显示、行走 和 事件发生 三个子模块,分别处理各自的功能。要注意这可是一个RPG游戏制作的难点哦!下面进行具体分析。

  (一)背景显示
  通常RPG游戏的场景是采用拼图方式生成的(如《仙剑奇侠传》、《金庸群侠传》等),拼图的好处是节省内存消耗、运行速度快和容易实现滚屏操作等。同时也减轻了美工的工作量,这点对我尤其重要。
  我们将计算机屏幕当成拼板,先把屏幕分辨率设为640x480x256色,然后用32x32大小的方格来划分它,这样整个屏幕就分成了15行乘20列的小格子(如图3所示),这就是我们用来表现游戏的舞台了。

 

  舞台搭建好之后,就可以在上面放我们需要的'道具',如:树木、石头、房子等等,将它们的大小都统一定为32x32,这样一个格子正好可以放下一个'道具';不过你一定会问:难道所有的道具都一样大吗?当然不一样,如果那样就太不真实了,我们把32x32作为最小的道具单位,比较大的道具可以占多个格子。如:一座山的大小为96x64,那么用3x2的格子来放置它就可以了。要注意的是所有道具的长和宽都必须是32的整数倍,这些需要你事先将它们处理好。

 


  请记住每个道具都要有它唯一的编号(如:树木=100、石头=101、房子=102、大山的编号是200~205共6个,因为它占6个格子)。这样当场景布置好后,我们的地图数据也就自然而然的产生了,如图4:
  以上就是场景编辑器的原理了(我在游戏制作前先写了一个场景编辑器,用来生成游戏中要用到的场景。场景编辑器附带在程序之中:MapEdit.exe),用场景编辑器设计好场景后先存在磁盘中,以便在游戏中调用。注意:道具的图片应事先制作好并存于另外的图形文件中。这里需要存储的仅仅是对应的数据,而不是真正的图片。
  搞清楚原理之后,要在游戏中生成场景就非常简单了,其实就是场景编辑的逆过程,一个是根据场景生成数据,而另一个是根据数据生成场景。我的算法如下:


MapData[20][15]; //事先用场景编辑器生成的地图数据
Picture[nums]; //道具的图片nums表示道具的总数
void MakeBackGround() //生成场景函数
{
 int n;
 for( int i=0; i<15; i++)
  for( int j=0; j<20; j++)
  {
   n=MapData[ i ][ j ]; //取得该位置的道具编号
   Blt( j*32, i*32, Picture[n]); //在此位置(j*32,i*32)画道具
  }
}

  一切就是这么简单,看着像图4一般的游戏场景,你的心情是不是非常激动?我想你一定和我一样吧!不过可别先忙着高兴,下面的内容会更精彩的。

  (二)行走
  舞台搭建好了,终于轮到我们的主角出场了(注意了!灯光、奏乐……),要让小飞刀在场景中自由自在的行走可不是一件容易的事,算算一共有上、下、左、右四个行走方向,每个方向3幅图(站立、迈左腿、迈右腿),所以要事先做好12幅图,如下:

 


  游戏中一定要将图片的背景设为透明,这样在画人物的时候就不会覆盖上背景色了(这一技术在DirectDraw中非常容易实现,只要将背景色定为ColorKey就行了)。
  其实让角色在场景上移动并不困难,只须改变他的屏幕坐标(x,y)就可以了,但是,一般的地图都比屏幕大的多,如果仅仅改变屏幕坐标的话,小飞刀不是就会走到屏幕外面去了吗?所以我们要让主角位置不动,而使场景移动。你是否注意到了《仙剑》中李逍遥一直就在屏幕的正中间?他行走时场景向着相反的方向移动。对,这就是滚屏技术的效果。
  地图是一张很大的画,而屏幕就是我们用来观察的窗口。利用我们先前讲的拼图方法就可以很容易的实现滚屏操作。只须引入一个相对坐标(SX,SY),表示当前屏幕左上角相对于整张地图左上角的位置。那么,生成场景时加入这个相对坐标就可以了,看看改进后的算法:

//场景生成算法
int W=100,H=80; //假如地图的大小为100*80个格子
MapData[W][H]; //事先用场景编辑器生成的地图数据
Picture[nums]; //道具的图片nums表示道具的总数

void MakeBackGround() //生成场景函数
{
 int n;
 for( int i=SY; i<SY+15; i++) //共15行
  for( int j=SX; j<SX+20; j++) //共20列
  {
   n=MapData[ i ][ j ]; //取得该位置的道具编号
   Blt( j*32, i*32, Picture[n]); //在此位置(j*32,i*32)画道具
  }
}

  怎么样?变化不大但是却很有效,这也正是游戏编程的魅力!这时要让角色移动就只须往相反的方向重绘背景就可以了,而角色一直保持在屏幕的正中间,需要做的工作只是根据行走方向和步伐不停变换图片而已。
  还要注意的是行走时的障碍物判断,因为有一些道具是不可跨越的,比如树木、房屋等。那么我们在行走时,应该先计算出下一步是否会碰到障碍,如果有障碍就取消移动。在这个程序中就是判断下一个格子中数据是否为0,因为0代表地面。
  好了,到现在为止,一套完整的行走系统就基本上出来了。运行一下,看看自己做的RPG游戏,感觉也不比别人的差嘛!看来只要是用了心,就会有好的心情!

  (三)事件发生
  不要忘了,这部分还有一个非常重要的功能,那就是事件发生了。其实原理非常简单,就是把相应事件的编号放在地图的某些格子中,那么,当主角一踏入这个格子就会触发对应事件。例如:
  我们设定游戏一开始时,小飞刀是在他的房间里。那么他要是想出去的话,就需要执行场景切换这个处理函数,但是应该在什么时候执行呢?这就需要触发一定的事件了。我们假定该事件的编号为1000,那么在地图上把门口处的格子值设为1000。这样无论小飞刀在房间里怎么走动都没有关系,而一旦他走到门口时,编号为1000的场景切换函数就会被触发,于是小飞刀便从屋内来到了屋外。
  类似的事件还有很多,踩到陷阱、碰到敌人、发现宝物等等……都可以用同样的方法进行处理,所不同的只是调用的函数。

  OK!最艰苦的时段终于熬过去了,现在就让我们以无比轻松的心情来回顾一下这几天的工作成果吧!
  首先,我们用拼图的方式建立了游戏的场景显示系统。
  然后,以滚屏技术实现了角色在场景上的移动。
  最后,了解了事件发生的一般原理。
  到目前为止,我们已经拥有了一个可以实实在在运行、真真切切感受的RPG了。不过现在的她才刚刚学会走路,还需要你用大量的营养来浇灌。这样就可以使她迅速成长,变的更加美丽动人!

四月二日:对话系统

  经常听见有人说"RPG游戏不就是一个小人在屏幕上走来走去,碰到了人就说两句话吗!"。虽然这种评价有点过于偏激,但是,也从一个侧面反映出了对话在RPG游戏的作用和影响。
  客观的讲,人物对话是表现一个游戏故事情节的最直接、最有效方法!而其他的任何手段都无法替代它。例如:过场动画也可以表现游戏的情节和发展,但是,过场动画最适合的是烘托整个游戏的气氛,交代游戏发生的背景或是作为两段情节间的衔接。而在表现游戏中的生活细节、情节线索或是人物心态时,它的作用就远远不如对话了。
  说到这里,我突然想说说近来关于游戏的一些感受。玩游戏也有几年的时间了,而在这几年玩过的游戏中,真正能让我难忘的经典之作好象并不多。而国内制作的更是寥寥无几(除《剑侠情缘》外基本上没有什么映像了),为什么这么多的游戏都不成功呢?我的最直接的感受就是--粗糙!不是讲画面的粗糙,而是游戏细节的不合理。
  举个例子:许多RPG中你可以随意进入别人家中翻箱倒柜而主人却毫不介意;敌人老窝里到处放有宝箱给玩家提供道具和强力装备……这都是不和理的地方。但如果说这些地方玩家们还可以接受的话。那么,当角色突然说出跟自己身份毫不相干的不伦不类的俏皮话时,我想这足以把你玩游戏的情绪破坏的干干净净。
  所以想对国内游戏制作公司说一句:当你们在宣传新游戏的投入如何巨大、技术如何先进、规模如何宏伟……的同时,请不要忘了把最基本的地方做好,多体贴一下玩家吧!
  好了,废话也说了不少,现在就言归正传。
  一般来说,游戏中的对话数据是和执行文件分开的,用了一个单独的文件来存储游戏中的所有对话数据,这样的好处是:修改对话数据时不必重新编译源程序!哪数据的组织结构是怎样的呢?应该说还没有一个统一的规范,各个游戏有都自己的方法,但不论采用哪种方法,只要能够使其简单清晰就可以了。请看下面的例子:

  例:这是一段主角和兵器店老板的对话摘抄:(摘自文件Talk.txt)
-----------------------------------------------------------------  =======兵器店======
  [59999]; //老板
  {是小飞刀啊,今天到我这里来想买点什么呢?}我随便看看!@;
  {我就知道你舍不得花钱,警告你不要打坏主意哦!}真是的!把我看成什么人了!@;
  {拿好了,欢迎下次再来!}还有下次,你就是请我来我都不来了!@;
-----------------------------------------------------------------
  第1行是注释,表明地点。
  第2行的[59999]是兵器店老板的编号,在游戏中用该号码唯一标示兵器店老板。
  第3行到第5行是三段对话,其中以 { 开头的话是老板说的,以 } 开头的话是主角小飞刀说的,每段对话用 @; 做结束标志。分析一下上述三段对话,我们不难看出:第1段话是小飞刀在买兵器之前和老板的对话;第2段是小飞刀没有买东西就要走,这时和老板的对话;而 第3段是在小飞刀买了东西后,他们说的话。
  具体在程序中的过程是这样的:当小飞刀走到兵器店老板面前时,我们按下对话按钮,这时程序得知对话对象的编号是[59999](即是兵器店老板),然后在对话数据文件Talk.txt中查找[59999]这个编号,寻找的结果就是上面我们摘抄的内容。执行第1段对话,然后就转入挑选兵器的界面,退出时程序会自动根据小飞刀有没有买东西而执行第2段对话(没买)或是第3段对话(买了)。很简单吧?短短的三段对话就表现出了一次买兵器的过程,而且通过这些对话,还刻画出了对话者的性格特点,可谓是一举多得了!
  这就是游戏中的对话过程,当然,我省略了其中的一些细节步骤,比如:怎样显示汉字、在什么位置显示等等。那是因为这些东西都很简单,自己翻翻书就可以了。


图6 小飞刀与兵器店老板的对话场面

四月六日:打斗和升级系统

  虽然"RPG"的字面意义"角色扮演游戏"和战斗似乎无关,但实际上,绝大多数的RPG都是有战斗存在的,因此,打斗系统就成为RPG系统中很重要的一环。通常在RPG中打斗和升级都是联系在一起的,所以就把它们放在一起介绍吧。先总结一下,现有的打斗方式不外乎有以下几种:
  一、回合制:这是最古老也是最经典的一种,自RPG诞生它就出现了,而且一直到今天这种打斗方式还经常被采用。它的特点是:简单、轻松,给了玩家充分的时间来思考。而且凭借它的回合制特点可以做出非常华丽的画面效果,给人一种轻松、休闲的享受。不足之处是:缺乏紧张刺激的感觉、真实性不强。代表作有:《仙剑奇侠传》、《侠客英雄传》和《剑侠情缘》等。
  二、战棋制:这种方式其实就是在回合制的基础上加入了类似棋盘的格子,人物可以走动,这种扩展带来的好处是:打斗时角色不是站在原地不动,然后你一拳、我一剑的拼血,而是可以玩出一些类似诱敌深入、个个击破的战术来。代表作是:《金庸群侠转》。
  三、即时制;现在最流行的一种方式,最大的特点是打斗时不用切换画面,直接在主地图上进行,给人的感觉是真实、刺激。不过实现起来难度要大得多,国外的大型游戏公司比较喜欢采用。其中的《暗黑破坏神》是最成功的一个例子。
  还应注意现在出现的一种所谓半即时的打斗方式,这其实也只是回合制的一种扩展,不应单独归为一类,代表作是《阿猫阿狗》。
  我列举这些打斗方式的目的不是想说明它们孰优孰劣,而是想告诉大家当你在设计RPG的打斗系统时,应该根据自己游戏的特点来进行选择,不要盲目的追求一种所谓流行的方式,要知道今天的流行并不代表在明天也会受欢迎,只有不断创新的东西才有旺盛的生命力。
  和打斗紧密相关的是升级,通常在一场战斗结束后,主角的经验值都会增加。而当经验值到达一定程度时,角色就升级了。这在程序实现上应该是非常简单的部分,但是很多游戏就是因为这部分处理的不好而大大降低了可玩性。为什么这么说呢?要知道我们玩游戏最希望碰到的就是和自己实力相当的对手,太强或太弱的对手都会使我们的兴致降低。所以在RPG中升级的快慢和幅度是一个相当难把握的尺度。必须通过大量的测试来调整,总之,一个原则就是不要让主角碰到的敌人和他相差太大。
  以上就是打斗系统和升级系统的介绍,希望大家能够在现有的基础上不断创新,让我们RPG游戏更加好玩。

结束语:
  好了,到次为止我们的RPG制作之旅也就告一段落了。如果你还有什么不清楚的地方或是有什么问题,就请通过电子邮件告诉我(wj77@163.net),或在我的主页面上留言(http://www.gpgame.com/),我一定会认真回复的。
再见!

http://yikenbbs.wigame.org/txt6/13.htm




DirectX学习手记(二)
happyfire 2002/8/11

此回说说怎样用DirectDraw向表面上贴图,包括创建离屏表面,设置调色板,载入位图到表面,透明色,页面丢失等。

二. 用DirectDraw贴图
先让我们回忆一下上一回的内容。为了初始化DirectDraw我们首先创建了一个DirectDraw对象,然后
设置了协作模式(全屏+独占),设置显示模式,然后创建主表面,提取后台缓冲表面指针。至此可以在后台
表面上进行操作,然后flip到前台显示出来。最后程序结束前释放所有的directdraw对象。好了,现在说说怎
样向后台表面贴图,即让屏幕显示图片。

第一步:创建离屏表面
离屏表面是你永远看不到的表面(所谓离屏),它通常被用来存放位图。通常的做法是把离屏表面
上的位图用Blt的方法贴到后台表面,后台表面再flip为前台表面。看看它的创建方法:

//声明用来存放图像的离屏表面(声明为全局变量)
LPDIRECTDRAWSURFACE lpDDSPic ;

//在InitDDraw()中创建保存图像的离屏表面
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH ;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN ;
ddsd.dwHeight = 480 ;
ddsd.dwWidth = 640 ;
if ( lpDD->CreateSurface(&ddsd,&lpDDSPic,NULL)!=DD_OK )
return FALSE ;

首先要声明一个表面,然后填充DDSURFACEDESC表面描述结构体。dwFlags填DDSD_CAPS表示ddsCaps域有效,
DDSD_HEIGHT和DDSD_WIDTH表示要指定页面的大小。ddsCaps.dwCaps填DDSCAPS_OFFSCREENPLAIN表示创建
的是离屏表面。dwHeight和dwWidth填页面的大小,单位是像素。然后就可以用DirectDraw对象的CreateSurface
方法创建lpDDSPic了。注意CreateSurface的第三个参数必须填NULL,该参数将允许与今后的 COM 集合特性相兼容。
整个创建过程和创建主表面非常相似,只是ddsd的填充不同。这里稍微谈一下离屏表面的大小问题。
在 DirectX 5.0 以前的版本中,离屏表面的宽度的最大值不能超出于主表面的宽度.而从 DirectX 5.0 版开始,你
可以创建任何宽度的离屏页面,只要你的显存和内存足够大.缺省情况下,离屏表面是被创建在显存中的,但如果
显存不够用,它就会被置于内存中,当然你可以指明只在显存中创建表面(可在 DDSCAPS 结构的 dwCaps 成员中
包含进 DDSCAPS_SYSTEMMEMORY 或 DDSCAPS_VIDEOMEMORY 标志符,以明确的表明你希望将表面置于何处),如果
这样的话,当表面太大而超出显存的容纳范围时,就会创建失败。
另外,以上面的方法创建的离屏表面的像素格式(可以简单理解为表示几位的颜色)是和主表面相同的,当然
也可以创建一个像素格式与主表面不同的离屏表面.然而,在这种情况下,该离屏表面将被限制于系统内存中。具体的
做法有点烦,各位感兴趣的可以查一下手册,:) 。

第二步:读入调色板并设置上
我们的主表面被设置为基于调色板(8位色深度)。一个基于调色板的表面是一些数字的集合,
其中的每一个数字代表一个像素.每一个数字的值都对应于一个色彩表(color table)中的项,这个表告诉 DirectDraw
对这个像素使用什么样的颜色. 这个表就是调色板(Palette)。使用调色板是为了尽量降低对显存的需求,它用一个
颜色索引(Color Index)来代表各个像素点的颜色,而不是直接用红,绿,蓝三基色的亮度值来确定每个像素点的颜色。
调色板包含了若干颜色索引和该索引所对应的真实颜色值。调色板的颜色索引主要采用4或8两种位深度。要在表面上
正常显示图像就必须将表面的调色板设置为该图像的调色板。如下面的代码片断:
//先声明调色板对象(其实是指针类型,就这么说吧,上面提到的各个对象都是这样的)
LPDIRECTDRAWPALETTE lpDDPal ;

//从位图设置调色板
lpDDPal = DDLoadPalette(lpDD, szBitmap);
if (lpDDPal)
lpDDSPrimary->SetPalette(lpDDPal);
else
return FALSE ;

DDLoadPalette是DDutil.cpp里面的函数,happyfire也不大懂,作为初学者拿来用就是了。


第三步:将位图文件读入已创建好的离屏表面中
这一步我们用DirectDraw APIs里面的一个函数DDLoadBitmap来实现,具体用法是:
lpDDSPic = DDLoadBitmap ( lpDD, szBitmap, 0, 0 ) ; //szBitmap是位图文件名,例如".\\pic\\background.bmp"
使用了DDLoadBitmap这一步变得非常简单,但是要把Ddutil.cpp和Ddutil.h加到工程中才行。你可以看看
Ddutil.cpp中该函数的实现,它调用了Windows的API LoadImage,并且用作为参数传进来的directdraw对象
创建了一个表面并返回了它的指针。

第四步:使用blit的方法,将离屏表面上的图片传送到后台缓冲
何谓blit?Bit block transfer(位块传送),即将内存中的数据块从一处传送到另一处。DirectDraw
提供了两个方法,Blt和BltFast。Blt功能强大,BltFast速度较快。这里我们先不讨论Blt,只用BltFast。看如何实现:

RECT rcRect ;

rcRect.left= 0;
rcRect.top= 0 ;
rcRect.right= 640;
rcRect.bottom=480;
lpddsBack->BltFast( 0, 0, lpddsPic, &rcRect, DDBLTFAST_SRCCOLORKEY|DDBLTFAST_WAIT);

RECT是windows的矩形结构(所以要包含windows.h),rcRect这个矩形用来确定源表面(这里是离屏表面)上的哪
一块区域要被传送到目标表面(这里是后台缓冲表面)上去。BltFast的前两个参数是两个DWORD值,表示目标表面
上的一个点的坐标x和y,它决定了传送过去的图形在目标表面上所处的位置。你可以改变x,y和rcRect看看效果。
最后一个参数是传送类型:
DDBLTFAST_DESTCOLORKEY
指定进行一次带透明的位块传送,使用目标表面的关键色(color key)。
DDBLTFAST_NOCOLORKEY
指定进行一次普通的复制,不带透明成分。
DDBLTFAST_SRCCOLORKEY
指定进行一次带透明的位块传送,使用源表面的关键色。
DDBLTFAST_WAIT
如果位块传送器正忙,延迟 DDERR_WASSTILLDRAWING 消息的发送,直到位块传送器准备好或发生其它错误时才返回。

看看这个color key,这可是很有用的!所谓关键色,即我们说的透明色,如果在源表面上指定了一个颜色为关键色,
那么在blit操作中,将视具有这种颜色的区域为透明,不会被传送到目标页面上。这样的话,虽然传送过去的是一个
矩形,但矩形上是关键色的部分是不会传送的,从而看上去是有轮廓的图形,比如一个精灵。

当然必须先为一个表面设置关键色才行。在InitDDraw中我们用DDSetColorKey ( lpDDSPic, RGB(255,0,255) ) ;为
创建好的离屏表面lpDDSPic设置了紫红色的关键色。你可以在图片中画一个精灵,然后把所有非精灵的部分用紫红色
填充。然后将BltFast的最后一个参数设为DDBLTFAST_SRCCOLORKEY.这样传送过去的就是一个精灵的样子了。

用DDBLTFAST_DESTCOLORKEY可以为目标表面设置关键色,有所不同的是,目标表面上颜色只有为关键色才能被覆盖,即
染色。

最后在说说目标表面和原表面的区别。其实它们都是相对的。调用BltFast的为目标表面,作为参数的为源表面。一般的
用法,后台表面调用BltFast,参数为离屏表面。

贴图的问题就说这么多吧,其实这里面的内容还是挺多的。还有非调色板模式的16位,24位,32位RGB格式,16位RGB对应于
不同的显卡还有555,565两种模式。但我们是初学者嘛,这些东西...:) 有待研究。(如果你真的立志于作游戏,呵呵,
准备学汇编吧,以后还要和MMX处理器的指令什么的打交道啊)

最后要说的是第四步的操作要放在MainLoop中,这样让它不停的Blt再Flip,如果你在程序中设计按了某个键贴不同的图并改
变贴图的位置,就可以做出精灵动画了,基本的原理就是这样的。

三.浅谈表面丢失的处理
如果你的程序从全屏模式下用Alt+Tab切出去,再切回来,你可能发现图片不见了。因为当代表页面内存的
DirectDrawSurface对象被不得已的释放时,与该对象相关联的页面内存也会被释放。当一个DirectDrawSurface对象丢失其
页面内存的时候,它的许多函数将返回DDERR_SURFACELOST,并且不进行任何其它操作。先看一下这个片断:
while (1){
hRst = lpDDSPrimary->Flip(NULL,0) ;

if ( hRst==DD_OK )
break ;

if ( hRst==DDERR_SURFACELOST ){

if ( RestoreAllDDS()!=DD_OK )
break ;
}

if (hRst != DDERR_WASSTILLDRAWING){
                break;
}
}

上回flip中没提到flip有失败的可能,上面的片断是解决的方法。如果flip返回DDERR_WASSTILLDRAWING,那么是由于上一次flip
操作尚未完成(flip指令已发出,但directX还没有完成操作),我们可以做的只能是让while循环下去,直到
hRst != DDERR_WASSTILLDRAWING。如果flip返回DD_OK,那表示flip操作完成,可以break出去了。如果flip返回
DDERR_SURFACELOST,表示发生了表面失效,这时我们需要自己处理它。看看我的RestoreAlDDS()函数是怎么工作的:

HRESULT RestoreAllDDS( void )
{
    HRESULT hRst ;
 
    hRst = lpDDSPrimary->Restore();
    if (hRst)   
hRst = lpDDSBack->Restore () ;
    if (hRst)   
hRst = lpDDSPic->Restore() ;

    DDReLoadBitmap ( lpDDSPic,szBitmap ) ;


    return hRst ;
}


在这个函数里面,我们先后调用了主表面,后台表面,离屏表面的Restore方法。Restore方法可以为这些丢失了内存的页面重新
分配内存,并且将这些内存与DirectDrawSurface对象联系上。但重建内存并不会使以前存在于该页面上的图象重新显现出来,
因此在调用Restore函数重建之后,必须亲手重新绘制所有的图象。在这里我用了DDReLoadBitmap函数,这个函数也是
Ddutil.cpp里面的。需要说明的是,如果用DDLoadBitmap代替DDReLoadBitmap是不行的!你可以看看这两个函数的实现,比较一下。

FROM : http://www.soudie.net/top_29719_cat_14/




    摘要:
 题记:玩了很多的游戏,不禁萌发了自己做游戏的念头,于是7月份从网上收集了N多资料。7月20几号在家开始了闭关式的学习,
一直到昨天,我的第一个地图类封装完毕,并乘胜追击到凌晨3点,做好了地图编辑器的0.9版。早上起来觉得有点累(才睡了几个小时,
呵呵),于是把这些天的学习经历回忆一下,权当是休息。这个过程是一个从对游戏编程一无所知到略识其理得过程,我想对于像我这样
的初学者应该有所帮助吧,至少可以少走些弯路。


一. 初识DirectX
在放假之前,我拜读了金点时空softboy的《圣剑英雄传--英雄救美制作手札》一文。此文简述了RPG游戏的基本原理,通俗易懂,
看完此文使人觉得游戏制作并非遥不可及,强烈推荐!但此文并没有提到有关DirectX编程的方法。所以做游戏,还要先过DirectX关。
于是我花了一天的时间,通读了老王翻译的《DirectX中文手册》,并分析了几个例程,在加上一个多星期的编程经历,总算有了一点感觉。

1.基础中的基础
此处阅读全文



在几年前我看到别人玩网络游戏用上了外挂,做为程序员的我心里实在是不爽,想搞清楚这到底是怎么回事。就拿了一些来研究,小有心得,拿出来与大家共享,外挂无非就是分几种罢了(依制作难度):
1、动作式,所谓动作式,就是指用API发命令给窗口或API控制鼠标、键盘等,使游戏里的人物进行流动或者攻击,最早以前的“石器”外挂就是这种方式。(这种外挂完全是垃圾,TMD,只要会一点点API的人都知道该怎么做,不过这种外挂也是入门级的好东东,虽然不能提高你的战斗力,但是可以提高你的士气^_^)
2、本地修改式,这种外挂跟传统上的一些游戏修改器没有两样,做这种外挂在编程只需要对内存地址有一点认识并且掌握API就可以实现,“精灵”的外挂这是这种方式写成的,它的难点在于找到那些地址码,找地址一般地要借助于别人的工具,有的游戏还有双码校验,正正找起来会比较困难。(这种外挂,比上一种有一点点难度,但是这种外挂做起来能够用,也是有一定难度的啦~~,这种外挂可以很快提升你对内存地址的理解及应用,是你编程技术提高的好东东)
3、木马式,这种外挂的目的是帮外挂制作者偷到用户的密码(TMD,“烂”就一个字,不过要知已知彼所以还是要谈一下啦~~),做这种外挂有一定的难度,需要HOOK或键盘监视技术做底子,才可以完成,它的原理是先首截了用户的帐号或密码,然后发到指定邮箱。(我以前写过这样的东东,但是从来没有用过,我知道这种东东很不道德,所以以后千万别用呀!~~)
4、加速式,这种外挂可以加快游戏的速度……(对不起大家,这种东东我没有实际做过,所以不能妄自评,惭愧~~)
5、封包式,这种外挂是高难度外挂,需要有很强的编程功力才可以写得出来。它的原理是先截取封包,后修改,再转发(Kao,说起来简单,你做一个试试~~~~)。这种外挂适用于大多数网络游戏,像WPE及一些网络游戏外挂都是用这种方式写成的,编写这种外挂需要apihook技术,winsock技术…………
  这几种外挂之中,前三种可以用VB,DELPHI等语言比较好实现,后两种则要用VC等底层支持比较好的编程工具才好实现。(啪,请听下回分解)
(本人是个程序爱好者并不是专业制作外挂的,所以文中有什么不当请大家海涵,以后的文章,我会依对动作式,本地修改式,木马式,封包式这4种东东的编写过程做详细解说)

版权说明:
您可以随意复制、分发、下载此文档。但未经本人同意,您不可以截取、改动本文片断,或用本文谋取任何形式的利益。

from: http://www.soudie.net/top_31308_cat_14/




只要调试过Full Screen模式DirectX程序的人都会对它心存恐惧,因为一旦运行到你预先设置的断点或是碰到
异常错误,在大多数情况下,都会让你的电脑死得很难看,除了重启,你没有别的办法。
  Imagic也是Full Screen模式的长期受害者,反复的重启让我的电脑也深受其害,以至于一碰到Full Screen模
式的程序都会先弹一个对话框“Are you sure?”(just a joke)。后来,Imagic终于摸索出一个土方法来解决这
个问题,效果很好, 终于可以使我坦然面对Full Screen程序。不敢独享,特放上来供大家参考。

  原理:将Full Screen模式程序改成Window模式
  方法:修改程序中的几个重要地方, 如:SetCooperativeLevel,SetDisplayMode,CreateSurface,Flip等
,使程序能够以窗口模式运行。一个很好的方法是用一个预编译的宏定义(如: FULLSCREEN_DEBUG)来控制编译
器,使程序能够很方便的在全屏模式与窗口模式下切换,下为一例:

  #ifdef FULLSCREEN_DEBUG
       lpDD->SetCooperativeLevel( hwnd, DDSCL_NORMAL);
  #else
       lpDD->SetCooperativeLevel( hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
       lpDD->SetDisplayMode( 640, 480, 16);
  #endif

  
一切完成并且确定没有错误之后,那么,在需要调试的时候,只需要:
  1、#define FULLSCREEN_DEBUG
  2、将显示器的分辨率设置成程序运行所需要的环境
  你就可以在窗口模式下很方便的调试你的DirectX Full Screen模式程序了(但是,这个方法只是针对DDraw程
序,对于D3D程序没有测试过)。

from: http://www.soudie.net/top_25203_cat_14/




[ZT]用PHP实现文件上传      

    在WebDev站点上经常看到的一个问题是关于文件上传的。在这篇文章里我将解释如何用PHP实现文件上传。  

  设计上传表格    

    我们主要的目标是完成文件从本地计算机上传到服务器上去。为了做到这一点,我们需要做一个表格,允许用户选择一个文件并可以提交它。下面是一个例子:
   
  <HTML>    
  <HEAD>    
  <TITLE>文件上传表格</TITLE>    
  </HEAD>    
  <BODY>    
  <TABLE>    
  <FORM   ENCTYPE="multipart/form-data"   NAME=MyForm ACTION=submit.php3 METHOD="POST">
  <TR><TD>选择上传文件</TD><TD><INPUT   NAME="MyFile" TYPE="File"></TD></TR>
  <TR><TD COLSPAN="2"><INPUT   NAME="submit"   VALUE="上传" TYPE="submit"></TD></TR>    
  </TABLE>    
  </BODY>    
  </HTML>    
   
    注意表格中的ENCTYPE="multipart/form-data"部分。这个一定不能错,否则服务器将不知道你在上传文件。    
   
  设计上传程序  
   
   现在我们已经完成了前台部分,让我们再仔细地考虑后台是如何接收文件并保存它到我们指定的目  
  录下去。下面就开始用PHP了。这是submit.php3的程序:
   
  <?    
  If($MyFile!="none")   {    
  copy($MyFile,"/home/berber/$MyFile_name");    
  unlink($MyFile);    
  }    
  else   {    
  echo"你没有上传任何文件";    
  }    
  ?>    
   
    不管你信不信,这就是整个处理过程。我们在程序中所做的就是:    
   
    1.   检查是否一个文件已经上传到服务器,通过If($MyFile   !=   "none");  
    2.   拷贝文件到指定位置。  
    3.   删除临时文件。  
   
    当你按下了提交按钮后,文件将会从你的计算机上传到服务器的临时目录下。在临时目录下的文件  
  名为一个临时文件。应该使用file字段的name值来访问它,在这里为$MyFile。真正的文件名使用file  
  字段的name值加上"_name"来访问它,在这里为$MyFile_name。使用copy()函数,将临时文件$MyFile拷  
  贝到指定目录下,拷贝后的文件名为$MyFile_name。完成后不要忘了删除临时文件,不然你会有许多你  
  不想要的文件。    
   
  设置文件名  
   
    一个可能让程序员睡不着觉的事情就是试图改变file字段的VALUE属性的值。并不是很多人知道它  
  是不可能的。尽管W3C说可以,但实际上,象IE和Netscape都不允许设置VAUE属性的值。听上去有点可  
  笑,为什么我不能设置一个初始值,这样让用户使用起来更方便呢?如果你那样做,那你就会发现你带  
  来了一个安全上的漏洞。可以设想一下,你登录到我的网站,我可以改变一个表格中的file字段的值。  
  那么有许能阻止我把你的/etc/passwd文件上传呢?更进一步的,我不需要你按下提交按钮,我可先设  
  置file字段的值,然后通过一段JavaScript程序来模拟提交动作...哇呜...我可以处理你机器上的任何  
  文件了。因为这个原因,浏览器简单地把<INPUT>标记中的file字段的VALUE字段给忽略了。    
   
  限制文件大小  
   
    另一个酷的特性是限制上传文件的大小选项。只要增加一个<INPUT>标记就可以了:  
   
  <INPUT   TYPE="hidden"   name="MAX_FILE_SIZE"   value="100000">    
   
    这个将不允许用户上传超过100KB的文件。  
   
  显示文件大小  
   
    为了显示文件大小,可以通过file字段name属性值加上"_size"这个变量来访问。在我们的例子中  
  就是使用$MyFile_size。所以,如果你想告诉用户上传文件的大小,你可以象下面那样去做:    
   
  echo   "You   have   just   uploaded   $MyFile_name";    
  echo   "The   size   of   the   file   is   $MyFile_size";    
   
  权限  
   
    很明显你需要对目标目录的写的权限。如果一个用户用匿文上传文件,那他的用户名应该是  
  "bobody"。这个用户必须有对目标目录写的权限否则你可能得到一个象下面的信息:    
   
  Warning:   Unable   to   create   "/home/berber/berber.txt":    
  Permission   denied    
  in   /home/berber/submit.php3   on   line   5




魔力NPC脚本解析

以下对于魔力的NPC解释是本人参照SA及魔力里具体的动作所作的解释
有部分语句无法理解,都写上了"未知"
可能有错漏,但由于没有可实际运行的服务器端,所以无法验证
在有可实际运行的服务器端我会补全的
转帖请注明chiu原创


CODE:
NPC的Create是在DATA目录下的npc.txt里实现的,由于没有可实际运行的服务器端所以无法具体解释npc.txt
NPC的对话是在DATA目录下的msg.txt里定义的,格式为:对话编号 对话内容

[Copy to clipboard]



CODE:
NPC类型:Event
[Copy to clipboard]



CODE:
判定语句:
block '判定语句
格式:block 判定条件
(用于出现对话框的条件 达到多个条件用 && 连接 多个条件中达到一个用 || 连接 下同)
Window_YES '对应Window里的按钮YES 判定语句
格式:Window_YES 判定条件
Window_NO '对应Window里的按钮NO 判定语句
格式:Window_NO 判定条件
Window_OK '对应Window里的按钮OK 判定语句
格式:Window_OK 判定条件
[Copy to clipboard]



CODE:
判定条件:
ItemSpace '检查道具空间 判定条件 用于判定语句后面
格式:ItemSpace == 数量 (等于)
  或ItemSpace >= 数量 (大于等于)
  或ItemSpace <= 数量 (小于等于)
  或ItemSpace != 数量 (不等于)
Item '检查是否拥有道具 判定条件 用于判定语句后面
格式:Item 道具编号 == 数量 (等于)
  或Item 道具编号 >= 数量 (大于等于)
  或Item 道具编号 <= 数量 (小于等于)
HaveItem '检查是否拥有特定道具 判定条件 用于判定语句后面
格式:HaveItem == 道具编号
Group '未知 判定条件 用于判定语句后面
格式:Group == 数量 (等于)
  或Group >= 数量 (大于等于)
  或Group <= 数量 (小于等于)
Gold '检查金钱数量 判定条件 用于判定语句后面
格式:Gold == 数量 (等于)
  或Gold >= 数量 (大于等于)
  或Gold <= 数量 (小于等于)
BBImage(BImage) '检测玩家图号 判定条件 用于判定语句后面
格式:BBImage(BImage) == 数量 (等于)
  或BBImage(BImage) >= 数量 (大于等于)
  或BBImage(BImage) <= 数量 (小于等于)
StrCmpChat '未知 判定条件 用于判定语句后面
格式:StrCmpChat == 数量 (等于)
  或StrCmpChat >= 数量 (大于等于)
  或StrCmpChat <= 数量 (小于等于)
CheckRealTime '时间 判定条件 用于判定语句后面
格式:CheckRealTime YYYY/MM/DD,TT:TT:TT == 0
(此处"0"的作用不清楚)
petlevel '检查特定宠物的等级 判定条件 用于判定语句后面
格式:petlevel 宠物编号 == 等级 (等于)
  或petlevel 宠物编号 >= 等级 (大于等于)
  或petlevel 宠物编号 <= 等级 (小于等于)
EquipItem '检查正装备着的道具 判定条件 用于判定语句后面(未确定)
格式:EquipItem == 道具编号 (等于)
CheckTitle '检查称号? 用法未知
Job '检查职业相关的 具体未知 判定条件 用于判定语句后面
格式:Job == 未知编号 (等于)
Fame 检查声望 判定条件 用于判定语句后面
格式:Fame == 数量 (等于)
  或Fame >= 数量 (大于等于)
  或Fame <= 数量 (小于等于)
HaveTitle '检查是否拥有称号 判定条件 用于判定语句后面
格式:HaveTitle == 称号编号 (等于)
TrialFlg '未知 判定条件 用于判定语句后面
格式:TrialFlg == 数量 (等于)
  或TrialFlg != 数量 (不等于)
NowTime '未知 时间相关 判定条件 用于判定语句后面
格式:NowTime == 数量 (等于)
  或NowTime != 数量 (不等于)
HaveLeak1Item '检查拥有道具相关 具体未知 判定条件 用于判定语句后面
格式:HaveLeak1Item == 道具编号 (等于)
ShipGetStopTime2 '未知 船相关 判定条件 用于判定语句后面
格式:ShipGetStopTime2 < 未知数值
Imagetype '图象相关 未知 判定条件 用于判定语句后面
格式:Imagetype == 未知数值
[Copy to clipboard]



CODE:
设定语句:
Window '对话框弹出
格式:Window 对话编号,按钮类型1,按钮类型2
(类型有YES NO OK CANCEL NEXT)
EndWindow '对应 Window 可单独使用
格式:EndWindow 对话编号(,按钮类型)
KillItem '交出道具
格式:KillItem 道具编号,数量
KillItemAll '交出全部的特定道具
格式:KillItemAll 道具编号
GiveItem '给予道具
格式:GiveItem 道具编号,数量
特殊用法:GiveItem (道具编号获得机率,道具编号获得机率,道具编号获得机率)[未确定]
eg:GiveItem (111%60,121%100,101%1)
  这里%60 %100 %1是获得的机率,111 121 101是道具编号
GiveLeak1Item '给予道具相关 具体未知
格式:GiveLeak1Item 道具编号,数量
特殊用法:GiveLeak1Item (道具编号获得机率未知,道具编号获得机率未知,道具编号获得机率未知)[未确定]
eg:GiveLeak1Item (18690%1$1,18693%1$1)
  这里%1 %1是获得的机率,18690 18693是道具编号,$1 $1未知
Warp '传送至
格式:Warp 0,地图号,X坐标,Y坐标
(这里0的作用暂时不知道)
LeaveGroup '脱离团队
格式 LeaveGroup
Encount '发生战斗
格式:未知
AddGold '给予或收取金钱
格式:AddGold 数量
(数量可以为负)
KillPetl '收走宠物
格式:KillPetl 宠物编号,数量
GivePet '给予宠物
格式:GivePet 宠物编号
ChangePal '未知
格式:ChangePal 未知数值,未知数值
SetHouse '未知 房子相关
格式:SetHouse 未知数值,未知数值
Message '对话
格式:Message 对话编号
SetLoginPoint '设定登陆点 具体未知
格式:SetLoginPoint 未知数值
Setaction '设定NPC动作
格式:Setaction 动作编号
playse '播放音效
格式:playse 音效编号,1,1
(这里1,1的作用未知)
[Copy to clipboard]



CODE:
判定及设定语句:
EndEvent '检查是否完成任务 判定条件 用于判定语句后面 或 作设定语句使用
格式:EndEvent 任务编号 == 0或1
(这里0为无,1为有)
NowEvent '检查是否正在进行任务 判定条件 用于判定语句后面 或 作设定语句使用
格式:NowEvent 任务编号 == 0或1
(这里0为无,1为有)
ShipCharTake '未知 船相关 判定条件 用于判定语句后面 或 作设定语句用
格式:ShipCharTake 未知数值,未知数值 == 未知数量
设定语句用法:ShipCharTake 未知数值,未知数值
ShipCharDown'未知 船相关 判定条件 用于判定语句后面 或 作设定语句用
格式:ShipCharDown 未知数值,未知数值 == 未知数量
设定语句用法:ShipCharDown 未知数值



上回对五种类型的外挂做了一个大体的概括,大家对这几种外挂都有了一定的了解,现在就依次(制作难度)由浅到深谈谈我对外挂制作的一些认识吧~~~~
首先,先来谈一下动作式的外挂,这也是我第一次写外挂时做的最简单的一种。
记得还在“石器”时代的时候,我看到别人挂着一种软件(外挂)人物就可以四外游走(当时我还不知道外挂怎么回事^_^),于是找了这种软件过来研究(拿来后才听别人说这叫外挂),发现这种东东其实实现起来并不难,仔佃看其实人物的行走无非就是鼠标在不同的地方点来点去而已,看后就有实现这功能的冲动,随后跑到MSDN上看了一些资料,发现这种实现这几个功能,只需要几个简单的API函数就可以搞定:
1、首先我们要知道现在鼠标的位置(为了好还原现在鼠标的位置)所以我们就要用到API函数GetCursorPos,它的使用方法如下:
BOOL GetCursorPos(

    LPPOINT lpPoint  // address of structure for cursor position 
   );
2、我们把鼠标的位置移到要到人物走到的地方,我们就要用到SetCursorPos函数来移动鼠标位置,它的使用方法如下:
BOOL SetCursorPos(

    int X, // horizontal position 
    int Y  // vertical position
   );
3、模拟鼠标发出按下和放开的动作,我们要用到mouse_event函数来实现,具休使用方法用下:
VOID mouse_event(

    DWORD dwFlags, // flags specifying various motion/click variants
    DWORD dx, // horizontal mouse position or position change
    DWORD dy, // vertical mouse position or position change
    DWORD dwData, // amount of wheel movement
    DWORD dwExtraInfo  // 32 bits of application-defined information
   );
在它的dwFlags处,可用的事件很多如移动MOUSEEVENTF_MOVE,左键按下MOUSEEVENTF_LEFTDOWN,左键放开MOUSEEVENTF_LEFTUP,具体的东东还是查一下MSDN吧~~~~~
好了,有了以前的知识,我们就可以来看看人物移走是怎么实现的了:

  getcursorpos(point);
  setcursorpos(ranpoint(80,windowX),ranpoint(80,windowY));//ranpoint是个自制的随机坐标函数
  mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
  mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0);
  setcursorpos(point.x,point.y);

看了以上的代码,是不是觉得人物的游走很简单啦~~,举一仿三,还有好多好东东可以用这个技巧实现(我早就说过,TMD,这是垃圾外挂的做法,相信了吧~~~),接下来,再看看游戏里面自动攻击的做法吧(必需游戏中攻击支持快捷键的),道理还是一样的,只是用的API不同罢了~~~,这回我们要用到的是keybd_event函数,其用法如下:
VOID keybd_event(

    BYTE bVk, // virtual-key code
    BYTE bScan, // hardware scan code
    DWORD dwFlags, // flags specifying various function options
    DWORD dwExtraInfo  // additional data associated with keystroke
   );
我们还要知道扫描码不可以直接使用,要用函数MapVirtualKey把键值转成扫描码,MapVirtualKey的具体使用方法如下:
UINT MapVirtualKey(

    UINT uCode, // virtual-key code or scan code
    UINT uMapType  // translation to perform
   );
好了,比说此快接键是CTRL+A,接下来让我们看看实际代码是怎么写的:

  keybd_event(VK_CONTROL,mapvirtualkey(VK_CONTROL,0),0,0);
  keybd_event(65,mapvirtualkey(65,0),0,0);
  keybd_event(65,mapvirtualkey(65,0),keyeventf_keyup,0);
  keybd_event(VK_CONTROL,mapvirtualkey(VK_CONTROL,0),keyeventf_keyup,0);

首先模拟按下了CTRL键,再模拟按下A键,再模拟放开A键,最后放开CTRL键,这就是一个模拟按快捷键的周期。
(看到这里,差不多对简易外挂有了一定的了解了吧~~~~做一个试试?如果你举一仿三还能有更好的东东出来,这就要看你的领悟能力了~~,不过不要高兴太早这只是才开始,以后还有更复杂的东东等着你呢~~)

版权说明:
您可以随意复制、分发、下载此文档。但未经本人同意,您不可以截取、改动本文片断,或用本文谋取任何形式的利益。

from : http://www.soudie.net/top_31309_cat_14/





    摘要:

上回我们对动作式外挂做了一个解析,动作式是最简单的外挂,现在我们带来看看,比动作式外挂更进一步的外挂——本地修改式外挂的整个制作过程进行一个详细的分解。
    具我所知,本地修改式外挂最典型的应用就是在“精灵”游戏上面,因为我在近一年前(“精灵”还在测试阶段),我所在的公司里有很多同事玩“精灵”,于是我看了一下游戏的数据处理方式,发现它所发送到服务器上的信息是存在于内存当中(我看后第一个感受是:修改这种游戏和修改单机版的游戏没有多大分别,换句话说就是在他向服务器提交信息之前修改了内存地址就可以了),当时我找到了地址于是修改了内存地址,果然,按我的想法修改了地址,让系统自动提交后,果然成功了~~~~~,后来“精灵”又改成了双地址校检,内存校检等等,在这里我就不废话了~~~~,OK,我们就来看看这类外挂是如何制作的:
    在做外挂之前我们要对Windows的内存有个具体的认识,而在    (全文共4508字)——点击此处阅读全文





    摘要:游戏外挂原理和技术分析(关于魔力宝贝)  
   
  注:本文曾被作为精华贴转于各大游戏论坛,最初于新浪魔力论坛发表  
     
  我认为网络游戏防外挂应该是从服务器代码上来控制的,要是代码写得好,BUG会很难  
  被玩家发现。我不赞成用外挂,但做网络游戏不能不研究。  
   
  根据我的理解说一下某些外挂的原理:  
   
  先是顺移外挂:  
   
     (全文共3110字)——点击此处阅读全文




    摘要:游戏外挂原理和技术分析(关于魔力宝贝)  
   
  注:本文曾被作为精华贴转于各大游戏论坛,最初于新浪魔力论坛发表  
     
  我认为网络游戏防外挂应该是从服务器代码上来控制的,要是代码写得好,BUG会很难  
  被玩家发现。我不赞成用外挂,但做网络游戏不能不研究。  
   
  根据我的理解说一下某些外挂的原理:  
   
  先是顺移外挂:  
   
     (全文共3110字)——点击此处阅读全文



GM帐号,密码修改,GM命令大全及使用。
*****************************************
crossgategmsvdatadebugger.txt 打开这个文件
开一个新行,把你在游戏中的帐户输入进去就行啦
比如我在游戏中的帐户是123456就象如下复制到里面。

_123456就复制到里面就是GM帐号咯。

注:修改GM帐号,GM密码统一,使用同一个密码,不能一个帐户一个密码。
*****************************************
打开crossgategmsvsetup.cf.XXX 打开这个文件
为1指定GM使用
chatmagiccdkeycheck=1
为0开放所有人物为GM [每个人都可以用GM命令]
chatmagiccdkeycheck=0

chatmagicpasswd=nr 
NR为GM的密码,可以自行修改密码的,可以改成如下,XXX是你要改的密码
chatmagicpasswd=xxx
*****************************************
在游戏中输入GM命令即可使用,GM命令格式为
[nr warp xxx xxx] 也就是移动到 xxx xxx 坐标
[nr setjob 职业ID]
[nr setskil 技能ID]
[nr setskilllv 技能位置 技能等级]

职业ID文件jobs.txt 
技能ID文件skill.txt
*****************************************




    摘要:魔力宝贝 韩国[乱码解析]宠物
http://www.seaomc.com.cn/viewthread.php?tid=145&extra=page%3D1
魔力宝贝 -> 韩国[乱码解析]~~~~~参照网页。相当全
甚至连问候语言都相当多。

001 野兽系 虎人 况鸥捞芭
002 野兽系 猫妖 墓矫
003 野兽系 罗刹 扼农箕荤
004 野兽系 猫人
005 野兽系 恶魔猫 扼农箕荤
006 野兽系 妖狐 饭捞# 钮福
007 野兽系 穴熊 纳捞宏 海绢
008 野兽系 赤熊
009 野兽系 北极熊 弃扼 海绢
010 野兽系 赤目黑熊    (全文共5994字)——点击此处阅读全文




    摘要:

cd /home
di
cd crossgate
cd gmsv
./gmsv
格式: [执行权限的密码 命令 参数]
如 [nr makepet 911]
解释一下。。 nr就是默认的执行命令的密码。 makepet是制造宠物的命令 911是LBLS的ID。
这样宠物栏里就有LBLS了。。。 也有好多不带参数 大家自行试验吧。

-------------------------------------------------------------------------------
GMcmd! 风中の草芥 测试&整理

sysinfo \\查看系统资料 如在线帐号数等。
metamo \\换形象 需要加参数;可以换任何形象 只要你知道形象的ID GM形象好象是100600
warp \\瞬移 格式: warp 人物ID 地图ID X坐标 Y坐标
followchar \\加CDKEY参数 得到帐号名并自动跟踪ID面前    (全文共3493字)——点击此处阅读全文




:准备

运行魔力宝贝服务器端所需要的程序

RedHat Linux 9.0

MySQL 4.1.16 for Linux

Ruby

Navicat(MySQL数据管理工具)

GCC编译工具

rogue数据库

2.安装RedHat

安装时一定要安装下面的组件

 

X 窗口系统

GNOME桌面环境

图形化互联网

开发工具

3:配置安装MySQL

打开终端 转到MYSQL 安装目录下 输入rpm -i mysql文件名 安装

默认用户名root 密码无

打开navicat

新建一名字为rogue的数据库,把rogue.sql导入


4.安装Ruby

解压ruby

打开终端,转到解压过的目录,运行如下命令

./configure

make

makefile

5.配置服务器

解压服务器端

用文本编辑器打开setup.cf文件

修改下面的几行

#blserv=211.232.109.164
#blserv=127.0.0.1
blserv=222.122.31.125
extraipaddress=211.17.202.194

把里面的IP改成本机的IP

dbpassword=zmftmcjsrnr

改成数据库密码(默认安装没有密码)

dbservname=dbsv

改成localhost

保存OK


6,运行服务器

打开终端,转到魔力服务端根目录下,输入./gmsv 

如果启动了.自动按gmsvlog的显示~

架设魔力所要滴程序
LINUX系统 推荐 REDHAT9.0

MYSQL   例如:   MySQL-client-4.1.21-0.i386   MySQL-server-4.1.21-0.i386   
          MySQL-shared-4.1.21-0.i386   MySQL-shared-compat-4.1.21-1.i386

SQL管理软件   PHPADMIN   Navicat (或者直接用命令)


WEB服务器     WIN下的IIS 或者 LINUX下的XAMPP


可能要用到的 LINUX下的 整合软件 RUBY GCC   CC


FTP FOR LINUX

魔力宝贝服务端 setup.cf 解释
#blserv=211.232.109.164 //bl 服务器地址
#blserv=127.0.0.1 //bl 服务器端口
blserv=222.122.31.125 //bl 服务器地址
blservport=1072 //bl 服务器端口
#blservport=9650 //bl 服务器端口
battledebugmsg=0 //战斗 debug 信息
battlenum=1000 //战斗最大值
CAinterval=500 //CAinterval
petmailmistakefile=data/petmailmistake.txt //宠邮错误文档
titleconfigfile=data/titleconfig.txt //主题设定文档
skillfile=data/skill.txt //技能文档
itemboxfile=store/itembox.txt //技能文档
protocolreadfrequency=200 //protocolreadfrequency
addressbookoffmesgnum=10000 //addressbookoffmesgnum
itemrecipefile=data/itemrecipe.txt //itemrecipefile
activedungeonfile=store/activedungeon.txt //activedungeonfile
dbquenum=500 //数据库查询最大值
enemyfile=data/enemy.txt //enemy文档
Itemdeletetime=21600 //文物去除时间
netiointerval=200 //netiointerval
autodungeonmapdir=store/dungeon/ //autodungeonmapdir
quizfile=data/question.txt //测验文件
maketimefile=data/maketime.txt //maketimefile
logdir=./log //记录文件
port=9030 //服务端端口
tobossnpcfile=data/tobossnpc.txt //tobossnpcfile
timeoutsafetime=600 //timeoutsafetime
timeoutchecktime=600 //timeoutchecktime
effectfile=data/effect.txt //effectfile
itematomfile=data/itematom.txt //itematomfile
logconfname=log.cf //记录设定文件
groupfile=data/group.txt //groupfile
guildmonstertextfile=data/guildmonstertext.txt //家族宠物文件
chatmagicpasswd=nr //GM指令密码
#objnum=30000 //物品数量
objnum=50000 //物品数量
battlerebirthfile=data/battlerebirth.txt //battlerebirthfile
ridepetfile=data/ridepet.txt //宠骑文件
magicfile=data/magic.txt //魔术文件
boltacnum=10 //boltacnum
fdnum=800 //最大连线数
nocompress=1 //nocompress
titlenamefile=data/titlename.txt //titlenamefile
servernumber=3 //服务端编号
#encountmemorynum=3000 //encountmemorynum
encountmemorynum=5000 //encountmemorynum
isaotrialcheck=1 //isaotrialcheck
warpfile=data/warp.txt //warp 地址
guisefile=data/guise.txt //guisefile
fctime=60 //fctime
loghour=0 //记录小时
harborfile=data/harbor.txt //海港设定文件
endofgmsvfile=gmsv.end //停止服务端文件
dbusername=root //数据库用户名
#mapjobnum=1000 //mapjobnum
mapjobnum=5000 //mapjobnum
encountfile=data/encount.txt //encountfile
itemboxentrynum=10000 //itemboxentrynum
#npccreatenum=6000 //NPC 创造时间
npccreatenum=10000 //NPC 创造量
npcfile=data/npc.txt //NPC 文件
shipadjust=0 //shipadjust
fccount=5 //fccount
Onelooptime=100 //Onelooptime
guildmonsteritemfile=data/guildmonsteritem.txt //家族宠物項目文件
#acpasswd=love.java //acpasswd
acpasswd=aho.java //acpasswd
dungeonconffile=data/dungeonconf.txt //dungeonconffile
isaocheck=1 //isaocheck
battlemapfile=data/map/battlemap.txt //battlemapfile
morphfile=data/morph.txt //morphfile
guildnum=50 //家族最大数
betaserver=0 //是否为测试服务端
techareafile=data/techarea.txt //techareafile
gameservname=Arzes //游戏服务端名字
#autodungeonnum=2500 //autodungeonnum
autodungeonnum=5000 //autodungeonnum
getSkillPopulationtime=9 //getSkillPopulationtime
usememoryunitnum=1600000 //使用记忆体单位
skillexpfile=data/skillexp.txt //技能经验设定
enemybasefile=data/enemybase.txt //enemybasefile
albumversion=4 //albumversion
nologinrankdown=604800 //nologinrankdown
enemymsgfile=data/enemytalk.txt //enemymsgfile
nodelay=1 //nodelay
tech_areafile=store/dungeontech_area.txt //tech_areafile
techareamemorynum=1024 //techareamemorynum
filesearchnum=5000 //文件搜查数
mlservport=9650 //邮件服务器端口
golddeletetime=3600 //金钱去除时间
CharSaveinterval=1800 //CharSaveinterval
checksyslogfile=syscheck.log //系统检查记录
itemingredientfile=data/itemingredient.txt //itemingredientfile
acserv=gmsv //用户服务器地址
saacreadnum=16 //saacreadnum
macrouserdown=1 //macrouserdown
chatmagiccdkeycheck=1 //使用GM指令前是否检查某用户是否有 GM 权限
mapjobfile=store/mapjob.txt //mapjobfile
guildmonsterfile=data/guildmonster.txt //guildmonsterfile
dungeonnpcfile=store/dungeonnpc.txt //dungeonnpcfile
housetime=120 //housetime
mouselist=60 //mouselist
mapdir=data/map/ //地图目录
dbservname=dbsv //数据库地址
fishfile=data/fish.txt //fish.txt
#othercharnum=9000 //othercharnum
othercharnum=15000 //othercharnum
skilllvfile=data/skilllv.txt //技能等级文件
boxcontainsfile=data/boxcontains.txt //boxcontainsfile
badmsgtxtfile=data/badmsg.txt //被禁止的言语文件
petnum=10000 //宠物最大值
jobs_ancestryfile=data/jobsancestry.txt //jobs_ancestryfile
makeseqfile=store/makeseq.txt //makeseqfile
rssfile=data/rss.txt //rssfile
walkinterval=250 //walkinterval
itemautofile=data/itemauto.txt //itemautofile
housenum=3000 //最大房间值
boltaclistnum=1000 //boltaclistnum
storedir=./store //storedir
time_free=0 //time_free
petmailimpossiblefile=data/petmailimpossible.txt //petmailimpossiblefile
saacwritenum=2 //saacwritenum
level_limit=120 //最高等级
CDinterval=500 //CDinterval
lsgenlogfilename= //lsgenlogfilename
authquenum=1000 //authquenum
mlserv=mlsv //邮件服务器地址
housecontractserver=1 //housecontractserver
morphpuk2file=data/morphpuk2.txt //morphpuk2file=data/morphpuk2.txt
msgtxtfile=data/msg.txt //NPC对诂文件
adjusttime=0 //adjusttime
dungeonencountfile=store/dungeonencount.txt //dungeonencountfile
enemyaifile=data/enemyai.txt //enemyaifile
itemmaterialfile=data/itemmaterial.txt //itemmaterialfile
materialmapdir=data/material_map/ //materialmapdir
injuryfile=data/injury.txt //损伤文件
rebirthfile=data/rebirth.txt //rebirthfile
guildmonsterrankfile=data/guildmonsterrank.txt //guildmonsterrankfile
mousecount=50 //mousecount
allowerrornum=20 //allowerrornum
acservport=9600 //ac服务端端口
maplogfile=log/mapid.log //地图记录文件
guildSaveInterval=60 //guildSaveInterval
unfairuserdown=1 //unfairuserdown
fcwait=300 //fcwait
shipfile=data/ship.txt //船文件
guildmonsterfavoritefile=data/guildmonsterfavor.txt //guildmonsterfavoritefile
itemnum=60000 //物品最大值
topdir=. //topdir
jobsfile=data/jobs.txt //职业文件
itemfile=data/itemset.txt //物品文件
geneboxratefile=data/geneboxrate.txt //geneboxratefile
dbpassword=zmftmcjsrnr //数据库密码
Petdeletetime=21600 //宠物去除时间
techfile=data/tech.txt //详细技术文件
usememoryunit=128 //usememoryunit
debuglevel=3 //debuglevel
petskillfile=data/petskill.txt //宠物技能文件
houseroomfile=data/houseroom.txt //houseroomfile
borderfile=data/border.txt //borderfile
maptilefile=data/map/newmapset.txt //maptilefile
breedingRoomSaveInterval=60 //breedingRoomSaveInterval
debuggerfile=data/debugger.txt //GM设定文件
socketreuse=OFF //socketreuse
extraipaddress=211.17.202.194 //服务器 IP
dbdatabasename=rogue //数据库名
housemapdir=store/house/ //housemapdir
version_conf=./version.conf //版本文件
daychargetouse=10 //daychargetouse
paymoneytoonce=100 //paymoneytoonce
beforemoney=300 //beforemoney
beforehandgivemoney=1000000 //beforehandgivemoney
guildItemBoxSaveInterval=60 //guildItemBoxSaveInterval
profilelist=data/profile.txt //profilelist
profileversion=3 //profileversion
aboutlist=data/aboutfile.txt //aboutlist
aboutversion=2 //aboutversion
mailcharge=100 //mailcharge




    摘要:[17175.cn首发]100条常用GM命令&解释!

转载请注明哦。。 [风中の草芥]   17175ID:librancj

如果还有其他大家研究出来的命令,要跟贴发出来共享啊。
有几个危险的命令 如踢所有玩家等的就不发了 此贴命令针对有权限的测试玩家。

格式: [执行权限的密码 命令 参数]
如 [nr makepet 911]  
解释一下。。 nr就是默认的执行命令的密码。 makepet是制造宠物的命令 911是LBLS的ID。
这样宠物栏里就有LBLS了。。。 也有好多不带参数 大家自行试验吧。

-------------------------------------------------------------------------------
GMcmd! 风中の草芥 测试&整理

sysinfo \\查看系统资料 如在线帐号数等。
metamo \\换形象 需    (全文共3595字)——点击此处阅读全文




    摘要:魔力深度中毒患者和心理医生的谈话  
某医院心理咨询科:  
医生:你怎么被送到这儿来了?  
患者:我到挂号台说我要找资深护士。  
医生:(精神病?)看来他们把你送到这里是对的。让我问你几个问题。  
患者:无论你问什么,我都选“是”。  
医生:我这些问题不需要你选择什么,而是要你回答的。你最大的理想是什么?  
患者:收破烂。  
医生:那可很没前途啊?  
患者:比医生有钱途。  
医生:开什么玩笑,如果没有医生,你生病了,找谁治啊?  
患者:鉴定师。  
医生:······(病得不轻),你都是一个人住吗?&nbs    (全文共1863字)——点击此处阅读全文




    摘要:

拦截winsock,锁血刷兰挂的制作方式
 
网络  未知 加入时间:2005-1-28 15:53:10  点击: 960
 
    拦截winsock,锁血刷兰挂的制作方式。
    一位台湾的同胞写的如何拦截winsock,进而对wsock32.dll动手术,不知对大家学习上次的锁血刷兰挂有没有帮助? 
   转载,敬请回复鼓励。
    [replyview]
    Windows 98动态连结函式库拦截技巧
    拦截 WinSock  
    前不久,实验室的学长遇到一个问题,他们希望可以拦截系统中有关WinSock send() 及 recv()的呼叫,也就是说在应用程式呼叫    (全文共14567字)——点击此处阅读全文





    摘要:Option Explicit 语句

用于在文件级强制对该文件中的所有变量进行显式声明。

Option Explicit { On | Off }

各部分说明

On
可选。启用 Option 此处阅读全文




    摘要:Option Explicit 语句

用于在文件级强制对该文件中的所有变量进行显式声明。

Option Explicit { On | Off }

各部分说明

On
可选。启用 Option 此处阅读全文




    摘要:

游戏修改器
 
■网络  ■未知 加入时间:2005-1-28 16:27:09  点击: 3399
 
      游戏修改器
      作者:CrackYY 
      开高级游戏黑客的面纱,教你打造游戏修改器 
      工具:SoftICE、金山游侠2002、VC++7.0、PE查看器、SPY++ 
      测试平台:Window2000 Professional SP2 

    将会用到的工具: 
      1、Soft    (全文共20308字)——点击此处阅读全文