游戏王ygocore吧 关注:244,035贴子:2,906,283

【教程资源】ygocore卡片添加教程完整版

只看楼主收藏回复

教程极长,楼下会分段发。
教程文件下载地址:http://pan.baidu.com/s/1dDeSTLf
也就是http://tieba.baidu.com/p/1498183366的完整版,补上了后面的章节。所以那个贴就别回了,免得挖坟。

我发这个教程链接之前,考虑过以下背景和因素:
①普及度——尽管网盘一直放着完整版教程,但是鲜被有需要的人注意到,从以前帖子的挖坟度、还有其它圈子推荐的残缺写卡教程上面可见一斑。
②入手度——从其它直接给出网盘下载地址的帖子上可以看出,大家都比较忙,如果不是拿起即看即用,效果可能不好,所以尽量在帖子里面发。
③需求度——每次一出新卡包,就有人表达希望ygocore立刻更新完,但这要在更新者翻很多倍的情况下才能做到。那么教程是关键。

如果有写卡方面的问题,请在看完教程之后再提问,否则可能很难解释清楚。
考虑到教程有点久远,故回复中可能会进行一些讨论,请有心者多花几分钟留意一下。
大家如果觉得有用,就顶起和相互转发,我会根据反馈考虑是否在置顶ygocore添加一些基本的开发和修复工具。


1楼2014-07-24 09:27回复
    另外,这个是添加教程而非说明文档,并且相关软件一直在更新中,比如DataEditorX更适合作为小白的编卡工具,所以详细说明、最新信息以这两个地址为准:
    http://ygocore.ys168.com/
    http://247321453.ys168.com/


    2楼2014-07-24 09:27
    收起回复
      2025-08-30 07:39:12
      广告
      不感兴趣
      开通SVIP免广告
      YGOCORE 游戏王CORE的自定义卡片教程(1)——第一章·基础篇(上)

      第一章:基础篇1.1 预备

      工具

      为YGOCORE添加自定义卡片和对应的卡片效果需要用到的工具有:

      DataEditor——卡片数据库添加软件
      这个软件是用来给card.cdb里登记卡片用的。YGOCORE只加载登记过的卡片,没登记过的卡片游戏中不存在。通常怪兽卡直接用这个软件添加即可在游戏中正常使用。这个软件要放到YGOCORE里的任意子目录中才有效,根目录会出错。
      下载地址:utility.7z 276KB

      Notepad++——文本编辑软件,编写lua脚本
      这个软件是用来编辑卡片lua脚本用的。编辑的时候记得要在格式菜单里面选择【utf-8 无BOM】编码,其他编码的lua脚本无效。

      图片编辑软件——修改卡图size
      YGOCORE的卡图有具体要求:大卡图必须177*254,小卡图必须44*64。超过这个尺寸,游戏中将报错。而各大卡查网站的公用卡图size是160*232,所以不能直接给YGOCORE用。

      作者提供的一些帮助文本
      作者已经别写了一个比较简略的说明文本讲解了如何添加自定义卡片,但是实在是太简略了,有很多细节没有详细说明。因此我才打算更详细的去写这个教程。虽然有我的教程,但是作者的帮助文本还是很必须的,毕竟我的教程是基于作者的说明来的。Script.txt是作者的说明文本,里面十分简陋而无序的说明了效果编写相关……。其中的function.txt里面记录了作者编写的各种函数的信息,为我们查找提供了方便(但是仍然漏了一些函数没有记录进去……)。

      知识
      这绝对是必须的,本教程只涉及YGOCORE卡片的添加过程和细节,但是lua脚本,lua语言我是不会讲的。
      那么是不是需要去了解lua语法?那是肯定的。但是没有必要精通lua,只要将lua的基本语法搞懂就行了,不会写也要会看会改。当然,最好有编程基础,这样看起代码来要高效得多。

      这些工具在游戏王YGOCORE贴吧的公共网盘里有提供下载:
      http://ygocore.ys168.com/
      位于相关工具目录
      utility.7z 276KB卡库编辑器+写卡说明||放入游戏目录的任意子目录来运行


      4楼2014-07-24 09:29
      回复
        YGOCORE 游戏王CORE的自定义卡片教程(3)——第一章续

        第一章续
        原本我是在第一章的第二节了里面准备了YGOCORE程序内部结构这一个内容的(这可是我辛辛苦苦看源码分析出来的),但是经过我深思熟虑我发现这内容除了我以外对于其他人没有任何意义……囧,所以就不贴出来了,只粗略的讲一讲YGOCORE里面会用到的自定义类型(其实就是面向对象里的类,这个不懂无所谓)

        2.1 自定义类型
        YGOCORE有三大自定义类型(就是YGOCORE自己定义出来的类型,面向对象里直接就是类的意思)YGOCORE里面各种处理的都基于这些类型的变量的。
        Card ——卡片类
        Group ——卡片组类
        Effect ——效果类
        这些类型都有成员变量(属性)和成员函数(行为)
        在lua里面调用这些类型的成员函数的方式如下
        卡片对象 : 对象成员函数
        C#######:GetXXXXXX()
        ※注意中间的冒号操作符,lua里面调用对象的成员函数都要这样做。而函数库里的函数调用就用点,例如Duel.Destroy()破坏某张卡。
        其实这不是严格上的解释,但是为了让大家快速入门,关于lua的语法特性我就能忽略就忽略。直接简单明了的说明。

        这三个类型里面最重要的是effect类,因为我们的效果就是effect类。我们写卡最有学问,最复杂,最耗时间,最头疼的就是写effect类的具体功能。所以我会详细的讲effect类。

        2.1.1 Card类是什么?
        Card类就是卡片类,YGOCORE在游戏开始的时候会从卡组deck文件里面读取 c+ID,然后以这个c+ID为名创建一个卡片对象,其实可以看做是card类型的变量吧。这个卡片对象有属于这个卡片的各种行为和属性。而我们YGOCORE的决斗系统Duel就是把弄这些卡片对象,将他们解放、破坏弄来弄去。Card类有什么属性(成员变量)有什么行为(成员函数),就到作者提供的function.txt里面查询(Set函数都是设置属性,Get函数都是获取属性)。由于Card对象不需要我们去创建和定义,所以我们根本就没要在意它需要设定什么值。只需要“拿来”就行了,用Get开头的成员函数获取一个现有的卡片的信息,然后对信息进行处理(主要是判断)。

        2.1.2 Group类是什么?
        Group类是卡片组类,不是卡组啊,是卡片组,卡组是Deck。卡片组是一堆卡片的集合,有些操作需要涉及到一组卡片例如卡片检索,需要将卡组里面符合条件的卡放到一起呈现在你面前让你选。这时候放到一起就放到了卡片组里面去了。这个类型跟card一样,我们不许要去设置,都是“拿来”(Get)。

        2.1.3 Effect类!高潮来了。
        这是最重要的类,我们的卡片的效果就是通过我们编写脚本来创建和定义这个类来实现具体的效果操作的。同时effect类也跟Card和Group一样可以“拿来”(Get)。
        以下是effect类的基本属性



        红色的属性conditioncost target operation就是效果的具体功能,他们都是函数需要我们自己去写实现代码,或者留空不设置。还记得我们的hello card么?hello card里面就没有设置这四个,但是依然可以用,可以发动效果。


        7楼2014-07-24 09:33
        回复
          2.2 YGOCORE三大函数库

          YGOCORE的脚本系统有四大部分组成(实质就是函数库)

          Duel ——决斗系统
          Card ——卡片系统
          Group ——卡片组系统
          Effect ——效果系统

          Duel决斗系统
          主要负责整个决斗环境,它相当于是“一双手“,拿起卡片,放下卡片,抽一张卡,选择卡片,擦看卡片,破坏卡片等等等等的这些“手操作”都是由duel中的函数实现的。也就是说想要让YGOCORE“动起来”,想要将那些卡片弄来弄去,就要靠这个。这四个系统里面与图形引擎最亲密的就是Duel,大部分我们能够看得见的操作都是duel函数的作用。而其他三个系统则比较隐性,一般我们察觉不到他们工作。同时效果的连锁也是由Duel来控制,效果1发动-》效果2连锁-》效果3连锁,这些连锁会被duel一一记录然后逆向处理。

          Card卡片系统——对应card类型的函数
          它负责的是卡片的一些操作,大部分的参数是用来获取卡片的信息的,获取后用来逻辑判断。

          Group卡片组系统——对应Group类型的函数

          Effect效果系统——对应effect类型的函数
          基本Card卡片系统,大部分参数用来获取效果信息,另外他还能获取这个效果所属的那张卡片card。


          9楼2014-07-24 09:35
          回复
            2.3 常量

            Effect类这就讲完啦?我还没弄懂呢?不必急,effect是个大学问,不是一两下就能弄懂的。在此之前要补一补另外一个知识——常量。

            还记得effect属性表里面,属性的中文名下方有些会带有大写字母的单词出现吗?那就是常量,属性的标识值。大部分属性都要用常量来设置。常量都定义在script\constant.lua 文件里面。当我们为自己的effect类Set属性的时候,从function.txt那里就可以看到这个属性应该用什么常量赋值。

            最常用到的值有effect属性值里的那些,然后就是REASON_了。

            重要常量

            EVENT是Effect类的一个属性,代表的是时点,效果什么时候发动就是这个来判断的。
            REASON是Card的一个属性,代表的是原因,我更喜欢称之其为“被XXX”。

            关于REASON可能大家很陌生,但是如果给它换个说法可能就容易明白了。REASON就是“被xxxx”的意思,是属于card的一个属性,意思是这个卡片“因什么原因”。还记得NDS或者PSP上面的游戏王,如果你打开墓第你会发现卡片上面都有一些图标表示其被送入墓地的原因——有“被战斗破坏”“被无效”“被破坏”等等。这些标识就是REASON的值。当效果e发动破坏某张卡的效果时,duel就会执行操作将那张卡破坏并给那张卡写入一个原因REASON,那张卡就有了个“因什么原因“而来到这个位置的信息。

            而以后我们的一些效果可能需要判断卡片的原因,例如”某个卡片被送去墓地的话可以发动这个效果,但是如果是被战斗破坏送去墓地的话就不能发这个效果“,这里就有个原因需要判断。

            CATEGORY是Effect类的一个属性,它代表着那个效果具有什么种类的效果,例如卡片破坏类,除外类等等等等。这类量很重要的原因在于,决斗系统duel的函数会用到这个。为什么?难道duel也有这个属性?duel不是一些函数而已吗?是这样的,duel就是“一双手“,我们玩弄卡片的操作就是靠着双手做出来的,而我们的行为是照着效果去做的。也就是说,效果说要破坏一张卡片,那么我们就做出破坏卡片的操作,但是这时候我们有必要“宣言”我们的操作。而这个CAGETGORY在操作中就是“宣言效果类别”,以供某些需要针对宣言来发动的效果判定之用,例如星尘龙的“破坏宣言"判定。

            小明:发动雪人的效果,雪人的效果是破坏场上一张卡。BOMB!——你那张卡片破坏!(小明指了指那张卡做出了破坏宣言)
            小王:啊?你要破坏我的卡片?确定?那我发动星尘龙效果,无效并破坏你那张卡。
            小明:啊~~~~NO~~~~

            从上是不是看出了什么眉头,没错,我们根据效果的类别做出同类别的行为,而这个行为需要作出宣言,这个宣言是以行为/操作的类别为依据产生的。这个宣言时点又会被别的效果捕获用来判断效果是否可以针对这个宣言发动效果。

            但是从上你会发现,效果的类别跟操作的宣言类别似乎是分开的,是的,效果的类别跟操作的宣言类别是分开的。一般情况下,我们的操作宣言类别都是跟效果类别一样,但是有时候会例外。有时卡片确实是破坏类别的效果但是我们却做出其他类别的宣言。有一个十分典型的例子,那就是那个经典的游戏王议题:星尘龙为什么不能无效潜行狙击手的破坏效果。

            哈哈,玩游戏王的人都知道这经典的议题。至于为什么,这里就留给读者自己去思考,我在第二章续——关于SetOperationInfo()函数会详细的讲解。


            11楼2014-07-24 09:43
            回复
              2.3.1常量的一些操作——这一部分可以先跳过
              这是附带讲解,常量也有一些操作,但是常量的操作十分的蛋疼……它的操作是二进制位操作。
              与操作/ +操作
              在用常量设置属性的时候,有时候需要多个常量组合起来使用,这时候要用“+”操作符。
              例如,效果类型EFFECT_TYPE_
              我们有些卡片的类型是“单体效果型+诱发必发型”例如三眼怪,这时候类型的设置就要将两种类型组合起来,那么就用“+”操作符EFFECT_TYPE_SINGLE+EFFECT_TYPE_TRIGGER_F
              ※那两个常量是什么意思可以暂时不用理会,又或者你好奇心旺盛可以直接去查constant.lua。

              2.3.2位操作
              这个是最蛋疼的部分……二进制位操作……但是又必须弄明白。希望大家忍痛看完。
              因为YGOCORE里面有一些地方做的实在是很不人性化,没有相关函数,直接用二进制来控制……
              例如区域,有时候我们需要设置某个区域不可用(不带选择的),但是YGOCORE没有SetDisableField(integerSequence)函数,更是没有区域序号Sequence的常量……所有的操作都要用1010的二进制来表示,这样想虫洞这张卡的最后的那个效果要实现起来就很头疼,实在是很痛苦。虽然最后还是让我给克服了(笑)。
              关于区域的操作以后会另开讲解。
              有时候我们需要过滤常量,例如REASON量
              我们知道有些常量可以互相叠加,REASON量里面REASON_EFFECT+REASON_DISCARD=REASON_EFFECT_DISCARD
              被效果 + 被丢弃 = 被效果丢弃
              0x40 + 0x4000 = 0x4040
              (REASON_EFFECT_DISCARD这个常量没有被定义进constant.lua里,是我自己瞎掰的)
              因此万一我们要判断卡片的原因reason属性里是否有这个原因,这时候不能直接
              r== REASON_DISCARD
              ※r代指卡片的reason属性
              因为REASON_EFFECT_DISCARD虽然也是DISCARD但是明显它与REASON_DISCARD的数值是不一样的。
              REASON_EFFECT_DISCARD(0x4040) ≠ REASON_DISCARD(0x4000)
              但是REASON_EFFECT_DISCARD(0x4040)却包含有REASON_DISCARD(0x4000)
              这时候我们需要过滤过滤出该卡片是否包含有REASON_DISCARD(0x4000)
              --最好的例子
              魔轰神里面被丢卡是指所有的丢卡,包括被代价丢卡,被回合丢卡,被效果丢卡,这时候就要判断参数r是否包含丢卡成分。
              我们可以用bit.band函数判断r中是否带有REASON_DISCARD
              这个函数的作用如下
              bit.band(A,B)== AB二进制相同的部分 or 0
              传入A,B两个数值,如果有相同部分就返回他们数值中相同的部分,如果没相同部分返回0。
              如 bit.band(0x4040,0x4000)=0x4000
              0x4040 100000001000000 0x4040
              0x4000 100000000000000 0x4000
              ————————————————
              结果 100000000000000 0x4000

              那么魔轰神判断代码就可以写成下面这样
              bit.band(r,REASON_DISCARD)==REASON_DISCARD——意思就是 r中是否含有丢卡成分
              你也可以不用这个办法,直接用组合的方式将所有REASON_DISCARD的组合给写出来
              如果你这样做的话我会鄙视你的。
              ※bit是作者写的辅助函数之一,说明在function.txt开头那里,我已经添加了更详细的注释。除了bit.band外还有bit.bor等其他4个位操作。这些bit函数的用法实在是奇葩,主要用于常量和卡片放置区域的运算或者其他什么底层的运算,因为这些量都是二进制数值表示的,要从中得出什么逻辑含义就只能二进制运算。除非是汇编级、整天对着二进制数的程序员,不然就算是那些高级编程语言者也会觉得这些函数很恶心。更别说那些不懂编程的小白了……直接就吐了。
              ※注意,常量是用16进制赋值的,但是他们对应的二进制值有个规律——那么多位里面只有一个1其余都是0。也正是如此才能利用二进制位运算来抽取数值中的信息。
              REASON_DESTROY
              =0x1
              1
              REASON_RELEASE
              =0x2
              10
              REASON_TEMPORARY
              =0x4
              100
              REASON_MATERIAL
              =0x8
              1000


              13楼2014-07-24 09:48
              回复
                2.4 两大基本效果类型

                YGOCORE里面有两大基本效果类型,对应于现实世界的游戏王其实就是按效果开不开连锁分类的:
                开连锁的效果——触发型效果(带有发动行为)
                不开连锁的效果——永续型效果(没有发动行为)

                他们之间还有个更加直观的区别。

                在YGOCORE里面,开连锁的效果都会在屏幕上显示放大了的自己的卡图,还有闪烁。(魔力之枷发动的时候开连锁。)
                而不开连锁的效果则没有。

                ※永续型效果不等于永续魔法陷阱卡的效果,其实“永续型”这个称呼有点混扰视听,我本人不是很赞同这个称呼,如果要我改个名的话,我会叫它作用/影响型效果。

                两大基本效果代码能发动起作用的最基本要求有:

                触发型效果:
                必须要有Type和Code。
                Type必须为EFFECT_TYPE_ACTIONS下方的任意一个类型。回想起我们的hello card,你就知道我们的hello card是触发型的效果。而e1第一个效果的Type就是发动型的意思。
                Code必须是EVENT_常量,是时点/事件的意思。

                永续型效果:
                必须要Type,Code、Range和Target Range。
                Type属性只能是EFFECT_TYPE_SINGLE(单体影响),EFFECT_TYPE_FIELD(群体影响)以及EFFECT_TYPE_EQUIP(被装备者影响)中的一个,不能与其他效果组合。Code是EFFECT_常量。Range是生效区域LOCATION值,TargetRange是作用区域也是LOCATION值。有一种奇葩的永续型效果是不需要range的,那就是全局效果,这个是实际写效果的时候会用到的技巧,不是基本效果之一。

                EFFECT_TYPE_常量



                最开始的那三个紫色的TYPE是永续型的TYPE,永续型效果的TYPE只能是这三个中的其中一个。绿色的那几个TYPE是触发型的TYPE,触发型TYPE里面只有TRIGGER(诱发)必须跟TYPE_SINGLE或TYPE_FIELD连用。

                触发型的property(附加性质)


                永续型的property值



                15楼2014-07-24 09:56
                收起回复
                  2025-08-30 07:33:12
                  广告
                  不感兴趣
                  开通SVIP免广告
                  2.4.1两大基本类型的基本代码

                  我曾经在hello card里面演示那短短的几段代码时说过,这几段代码是效果能够发动的最基本代码。其实那几段代码就是是触发型效果能够发动的最基本代码。

                  但是如果你试一下将那张自创卡的YGOCOR卡库里面的卡种改成永续魔法卡,看看会发生什么事?哈哈,这张魔法卡发动完后就像永续魔法卡那样留场了!没错,还记得准备篇我怎么解释DataEditor的作用的么。DataEditor将卡片的基本信息录入卡库,热这些基本信息决定了卡片在YGOCORE里面的基本行为。我指的就是卡片的种类决定了卡片的行为。如通常/速攻魔法卡发动完后就扔墓地不会留场,永续魔法卡发动后除非被破坏或者送去墓地不然会一直留场。

                  YGOCORE的这一个性质的意义非凡啊,还记得【2.1.3 effect类】的属性表里面的Range-生效区域属性么。规定了该效果需要卡片在哪个区域正面表示时才生效。所以如果给通常/速攻魔法卡添加永续型效果毫无意义,因为它根本就不留场。不过你可以把Range设置成墓地LOCATION_GRAVE,这样的话卡片在墓地效果就能生效。

                  好了言归正传,这两种类型的基本代码其实从要求那里已经能够看出了,只要将他们最低限度最低要求的代码写出来那么这个类型的效果就能发动。

                  样板

                  --触发型
                  local e1=Effect.CreateEffect(c)
                  e1:SetType(EFFECT_TYPE_ACTIVATE)
                  e1:SetCode(EVENT_FREE_CHAIN)
                  e1:SetOperation(c19903192.op) –调试用
                  c:RegisterEffect(e1)

                  --永续型
                  local e2=Effect.CreateEffect(c)
                  e2:SetType(EFFECT_TYPE_FIELD)
                  e2:SetCode(EFFECT_CANNOT_ATTACK)
                  e2:SetRange(LOCATION_SZONE)
                  e2:SetTargetRange(LOACATION_MZONE,LOCATION_MZONE)
                  c:RegisterEffect(e2)

                  2.4.2 Hello Card 2.0!

                  现在我们为当初写的那个HelloCard 添加一个最基本的永续型效果。做法跟上次一样,不过这次为了让卡片留场,我们要修改卡库里面Hello Card的卡种,改成永续+魔法。

                  然后往lua脚本里面这样写
                  --hello card
                  function c19903192.initial_effect(c)
                  --Activate
                  local e1=Effect.CreateEffect(c)
                  e1:SetType(EFFECT_TYPE_ACTIVATE)
                  e1:SetCode(EVENT_FREE_CHAIN)
                  e1:SetOperation(c19903192.op) –调试用
                  c:RegisterEffect(e1)
                  --effect
                  local e2=Effect.CreateEffect(c)
                  e2:SetType(EFFECT_TYPE_FIELD)
                  e2:SetCode(EFFECT_CANNOT_ATTACK)
                  e2:SetRange(LOCATION_SZONE)
                  e2:SetTargetRange(LOACATION_MZONE,LOCATION_MZONE)
                  c:RegisterEffect(e2)
                  end

                  function c19903192.op(e,tp,eg,ep,ev,re,r,rp)
                  Duel.SelectYesNo(tp,1)
                  end

                  e1就是触发型效果的最基本代码,e2就是永续型效果的最基本代码。
                  以后我们写效果都是用这两种类型的效果不断细化组合出更具体的效果。
                  是否注意到这次的hello card里我为我们第一次写的效果e1加了一段代码?

                  e1:SetOperation(c19903192.op)
                  效果初始化函数下面还有个function c19903192.op(……) 函数的定义

                  回到【2.1.3Effect类】那一节回顾一下operation是什么属性,没错,operation就是卡片效果处理操作,是一个函数,而我在这里定义的c19903192.op函数就是效果的效果处理函数,负责处理效果的操作。

                  这次这个函数里面只调用了Duel.SelectYesNo(tp,1),作用就是效果处理的时候弹出选一个是/否对话框,供玩家选择。


                  它在这里的实际用处是用来检查operation函数有没有被执行,换句话就是这个效果有没有真正的发动和处理。但是在正式写效果脚本时,这个函数是用来跟玩家交互的,也就是获取玩家的选择。

                  现在赶紧去测试你的hello card,你会发现hallo card发动的时候弹出了这个对话框,证明效果发动并且真的处理。

                  但是永续型效果却无法用这种方式调试,因为永续型效果一般不带operation。这就惨了,我怎么知道自己写的永续型效果有没有起作用?这就要慢慢来了。一般是先用容易检测到的永续型效果来测试基本代码是否无误,然后再修改成更具体的代码,这里涉及到效果脚本的调试请看2.5效果脚本的调试。

                  ※再提供多一段代码给你,将这段代码添加到hallo card里看看。

                  local e3=Effect.CreateEffect(c)
                  e3:SetType(EFFECT_TYPE_TRIGGER_F+EFFECT_TYPE_FIELD)
                  e3:SetCode(EVENT_TO_GRAVE)
                  e3:SetRange(LOCATION_SZONE)
                  e3:SetOperation(c19903192.op)
                  c:RegisterEffect(e3)

                  在测试之前你能不能看懂这个效果什么意思?


                  17楼2014-07-24 09:59
                  回复
                    2.5 效果脚本的调试

                    这是很重要的环节,虽然我们还没有详细的讲解到condition target cost operation函数的具体细节,但是以目前学到的知识,各位其实都已经可以去设计没有实际操作但是又可以发动的空效果effect了,例如我们写的hello card。通过不断的尝试各种各样的效果组合来了解各种效果的运作特点在正式编写效果脚本前是很有意义的。

                    由于路飞君的提点,重新修正了脚本调试的方法。

                    有一点要注意:在上面我选了Duel.SelectYesNo作为调试用函数,来测试operation函数有没有被执行。但是这个函数只允许在Cost,Target和operation这三个函数里面使用,condition是不能加这个函数检测的。

                    人非圣人孰能无过,尤其是像我们没有专用编译器帮你差错,直接在文本编辑器上面码代码,很容就写错字,弄错标点什么的,效果不能发动或者发动了不起作用。这时候就要靠YGOCORE去帮你找出脚本中哪一行出错。

                    开启YGOCORE的Debug模式(调试模式)
                    给YGOCORE创建一个快捷方式的目标文件那里添加–Debug 这几个字


                    这样YGOCORE的调试模式就开启了。
                    测试卡片的时候,脚本的错误都会记录在YGOCORE根目录的error.log文件里面。
                    现在我们试一下将SetOperation函数里面的c19903192.op删掉,保存然后测试卡片。


                    这时候打开error.log,找到自己的lua脚本。这两句就是调试信息,写明了是什么错误。
                    [Script error:][string “c######.lua”]:行号错误原因
                    重要的是行号和错误原因,我们直接根据行号查看自己lua所在那行代码,然后根据错误原因去检查哪里出错。

                    Error.log里面说我的lua脚本第8行缺少了个function参数。打开一看,第八行SetOperation还真的少了个operation函数参数(废话……不刚才自己弄得么)

                    拼写错误的话error.log是怎么提示的?


                    信息显示第5行 SetTpe 呼叫失败。看到这个难道还不明白么。

                    如果我们将符号常量写错了会怎么样?
                    我将SetType的EFFECT_TYPE_ACTIVATE写成了EFFEC_TYPE_ACTIVATE。测试一下。

                    没有产生新的调试信息,我写错了符号常量但是YGOCORE却没有检测出则个错误。

                    看来YGOCORE是不会检查符号常量的拼写错误的。这里就要注意了,这种错误要靠自己去排查检查。不过一般代码没写错,那么就肯定是符号常量有错。

                    脚本编写与调试步骤(各个阶段都要配合error.log调试信息)

                    第一步:先将效果的最基本代码写出来。其实就是hello card的那种,只把能发动效果的最低限度的代码写出来。然后测试,看能不能够发动。
                    第二步:为添加调试用operation函数,调试函数就用duel.SelectYesNo()来充当。然后再测试,看看效果发动后有没有进入处理。target,cost也用这种方法。
                    第三步:通过error.log调试condition。
                    第四步:代码的具体实现阶段。condition target cost operation这四个函数畅通无阻后,就开始往里面编写具体的处理代码。这时候的调试就主要依靠error.log调试信息了。当然在target cost operation这三个函数里面,我们也可以使用调试函数来按步跟踪。

                    按照以上的步骤我们就将代码debug分成了四个阶段,再配合YGOCORE提供的error.log调试信息,消除bug也就更准确方便了。到时候,只要对应哪个阶段去检查该阶段的代码即可。

                    要养成经常检查error.log的习惯。


                    19楼2014-07-24 10:05
                    回复
                      YGOCORE 游戏王CORE的自定义卡片教程(4)——第二章·进阶篇(上)

                      第二章 进阶篇

                      上一章是入门,让大家体验了下如何为卡片添加效果。但是真正要学会添加具体效果仅仅靠那些三脚猫功夫是远远不够的。我们还需要了解一下YGOCORE的运作过程,接着要了解效果effect代码的基本样式。

                      2.1 YGOCORE的运作机制

                      运作机制有纵向和横向两个过程

                      --==纵向过程!

                      --触发型效果进入连锁的操作
                      系统发出事件消息 EVENT_XXX
                      第一步、检查时点 EVENT_XXX CODE 触发阶段
                      --进入效果
                      第二步、检查条件 不满足前提条件不能发动 检查阶段
                      第三步、检查和处理对象 设置operation信息OperationInfo(操作信息,包括宣言) Target ※ 对象不存在则不能发动
                      第四步、检查和处理cost Cost ※ --处理效果
                      第五步、效果的处理操作 Operation 操作阶段
                      --此时系统根据Operation的OperationInfo里CATEGORY信息在连锁中“发出宣言”
                      --退出效果
                      控制权返回系统
                      系统自己又会根据当前情况继续发出各种事件消息 EVENT_XXX
                      如此循环

                      --不进入连锁的永续型效果
                      第一步、检查生效范围 LOCATION_XXXX range
                      第二步、检查条件condition 前提条件不满足则不生效
                      第三步、检查和处理cost
                      --处理效果
                      第五步、效果的处理操作 Operation

                      --==横向过程

                      值得一提的是! YGOCORE是先按步,再按卡片顺序的进行处理的。
                      例如我们场上有 3张卡 A B C
                      那么YGOCORE就
                      先依次检查ABC是否满足时点 --第一步
                      再依次检查ABC是否满足前提条件 --第二步
                      再依次检查ABC是否存在对象 --第三步
                      再依次检查ABC是否有满足cost --第四步
                      最后依次执行ABC的处理操作 --第五步

                      ※从这里知道,如果一张卡片能否发动依次取决于前三步是否都满足,如果自己编写的效果lua脚本满足了各种条件的情况下仍无法发动则应当去检查前三步所涉及的函数及其代码是否有误。而之前就说过,这三个函数可以留空不写,留空则表示永远满足。


                      22楼2014-07-24 10:14
                      回复
                        2.2 主角登场——效果类型effect脚本


                        我们在两次的Hello Card里面已经写过最基础的“空效果”——只有发动而没有实际功能的效果。其实已经对effect效果的创建过程有了比较清晰的认识。但是一个真正意义上完整的效果往往十分复杂,有很多细节。


                        我们就拿魔轰神兽刻耳柏拉,那只三头猫(应该是猫吧)的效果来作说明,注意这个效果是触发型效果。


                        一个效果里面往往有很多的信息,包括了时点code,前提条件condition,目标对象target,操作operation等。时点code是指这个效果能够被触发的时间,前提条件condition是这个效果能够发动的前提,目标对象target是这个效果作用的目标(目标不存在不能发动,也就是空发不能),操作operation是这个效果的最终处理操作。


                        对于魔轰神兽的效果,我们可以从中抽离出上面几点信息。


                        这张卡(type:EFFECT_TYPE_SINGLE)从手卡(condition)丢弃(reason:REASON_DISCARD)去墓地时(code:EVENT_TO_GRAVE),这张卡在自己场上特殊召唤(operation:SpecialSummon,LOCATION_MZONE)。(由于没有可以两个字,所以是type:EFFECT_TRIGGER_F诱发必发)


                        整理出来后就是以下:
                        Code时点:进墓地时
                        Type类型:只针对这张卡SINGLE+触发必发型TRIGGER_F
                        Condition:进墓地前在手卡+被丢弃
                        operation:发动效果的这张卡+表侧表示+特殊召唤+自己场上
                        Target:好像没有


                        噔噔!一下子就抽离出了这么多信息,effect的脚本编写其实就是将这些信息填充进我们的空效果里面。


                        然后去看看魔轰神兽的初始化效果部分代码:


                        红色部分就是我们跟我们抽离出来的信息相吻合的部分,紫色的则是我们漏掉的信息,原来effect效果还有个属性叫做效果类别Category,而魔轰神兽的效果的效果类别是特殊召唤类。


                        另外,明明这张卡没有作用于目标对象,为何要有Target,因为目标对象也可以是自己啊。而且触发型效果的Target跟Operation总是成对出现的。关于这个最后面会讲到。涉及到宣言。


                        23楼2014-07-24 10:17
                        回复
                          2.3 effect脚本的基本格式


                          说是基本格式其实只是为了让初学者有一个规范,不然乱七八糟的语句除了会产生各种各样的bug外还让脚本的编写困难重重。


                          --效果属性的设置在initial_effect()函数里面
                          --效果的处理函数在下面定义
                          --有时候我们还需要自己定义一个卡片过滤函数filter用来反复调用过滤卡片。
                          --需要设置的基本属性值和设置方法请看下面第一部分.
                          --需要定义的处理函数请看下面


                          ※一个卡片的效果可能由很多个效果组成,而每个效果的触发条件之类的属性都可能各不相同。
                          而像永续魔法卡还需要一个独立的发动效果--Activate
                          该效果可能没有效果处理行为,作用仅仅是将卡片翻开发动而已。请回忆起我们的hello card。
                          关于“各种卡片的效果的基本模板”,这个另外讲解。


                          最初的时候我就讲过YGOCORE是如何创建卡片Card类型变量然后将效果注册给卡片card的:先根据卡组信息读入c+ID然后根据这个ID创建card对象,接着根据script目录下对应的脚本初始化效果e1 e2 e3……依次将效果注册给这个card变量(绑定)。这只是游戏开始时效果初始化的做法,我说过效果也是YGOCORE里的一种类型,也是变量,所以效果是可以动态创建和动态绑定(注册)的——“随时随地”按需要给卡片注册一个新效果。这个特性也经常会用到——全局效果和效果标记,这个以后会独立的讲到。


                          关于效果属性的设置可以直接去第一章effect类的基本属性表那里查看,接着到function.TXT里面查找effect类对应的Set函数,根据说明调用即可。这里我就不多讲了,因为有的查。


                          24楼2014-07-24 10:19
                          回复
                            2.4 condition、cost、target、operation、value这五个函数的相关讲解。
                            还记得上面魔轰神兽我们所抽离出的信息么,一般情况下抽离出来的信息都会涉及上面五个函数中的某几个。魔轰神兽就涉及到了condition前提条件、target目标对象和operation操作处理,这三个函数。魔轰神兽效果的具体的细节就在这三个函数里面编写。
                            首先他们五个都有对应的Set函数。

                            函数与参数列表



                            ※触发型效果跟永续型效果的参数略有出入
                            ※触发型效果condition最终需要返回一个boolean型数据,true表示满足条件,false表示不满足。
                            Target,cost第一条语句必须if chk ==0 then return 条件 end这样,用于判断可行性,防止空发。(如果cost里面没有进行可行性判断,先判断能否支付代价的话,就会出现支付超出LP的代价把自己弄死的囧情况)
                            如果三条函数不Set、留空则认为总是满足条件。
                            operation中进行实际的效果处理,并且不需要返回值。
                            ※永续型效果的operation可能有返回值。永续型效果的target cost没有chk参数所以不用判断可行性。但是与此同时永续型效果的target和cost反而需要返回值。而这里target和cost跟condition一样成了operation的前提条件。
                            ※蓝色背景色部分表示这些参数描述了事件/时点的相关信息。
                            ※触发型和永续型的参数有所不同,c、g、gc,te_or_c是永续型效果才有的参数。


                            26楼2014-07-24 10:25
                            回复
                              2025-08-30 07:27:12
                              广告
                              不感兴趣
                              开通SVIP免广告
                              YGOCORE 游戏王CORE的自定义卡片教程(4)——第二章·进阶篇(下)
                              为什么触发型和永续型的condition等函数的参数会有所不同?
                              这是因为触发型和永续型他们所涉及的事件信息不一样。
                              触发型的效果涉及的事件信息有:
                              作用了哪个卡片组event group、作用了哪个玩家event player、事件的参数值value、因哪个效果reason effect、因什么原因reason、因哪个玩家reason player。
                              就是蓝色的那几个参数。
                              举例来说:
                              玩家1发动某效果e1对玩家2造成了500的效果伤害,那么这时候就会产生事件信息。
                              eg:空——没有作用于哪个卡片组
                              ep:1 (1=玩家2)——作用于玩家2
                              ev:500 ——事件有500的数值
                              re: e1 ——因效果e1
                              r: REASON_EFFECT(效果伤害)——因效果伤害
                              rp: 0 (=玩家1)——因玩家1
                              触发性效果的那几个函数就是将这几个值传入函数。
                              而永续型效果由于只有影响作用所以它涉及的事件信息只有:
                              作用的卡片card、作用的卡片组group、作用的卡片组数目group count、作用的效果effect或card、这个效果的玩家this player。
                              ※tp(this player)不是指该回合的玩家,而是指那个开了连锁的效果所属的玩家。例如在自己回合对方发动了陷阱卡,那么就开了个连锁,这时候事件信息里面的tp就是对方。
                              ※要注意,无论触发型还是永续型,operation的参数都是一样的。
                              函数样板

                              ※有chk参数的函数都第一条语句都先判断chk,chk默认为0,意思是不可行,这个是用来设置门槛防止效果空发的。在target函数里,例如一个效果要选择场上一张卡破坏,那么场上就必须有卡,而且那卡是可破坏的,这时候我们才可以发动效果。在这里目标对象就是场上的一张卡,要是目标不存在的话就不发动。在target里Chk就是负责检查可操作对象是否存在。在cost函数里则是负责检查能否支付代价。他们的共同点就是检查可行性。例如我们只剩下1000LP这时候总不可能还能发动神警吧,难不成透支代价而死么?所以这里就有了这样一段语句:
                              if chk == 0 return Duel.CheckLPCost(tp,2000)
                              这位玩家能否支付2000LP作为cost。
                              永续效果型的cost里面没有chk参数,所以不需要判断chk,但是永续型效果的cost有bool值,也就是说要 return条件 end 给他返回一个真假值。
                              ※如果触发型效果的operation带有某种类别如破坏会引发相应的事件、除外等等,那么target函数要为operation函数设定操作信息,调用函数Duel.SetOperationInfo(),其中一个参数是“操作的类别”,而cost函数不需要SetOperationInfo。
                              =====================================================================
                              好了,知道了这5个函数的相关知识后,我们可以拿魔轰神兽了来练练手。怎么练?那就是自己分析魔轰神兽那张卡的效果然后写出伪代码(中文意思的代码),最后再去对比一下自己的代码跟原效果代码。
                              以下是我们之前从效果说明中抽离出来的信息
                              Code时点:进墓地时
                              Type类型:只针对这张卡SINGLE+触发必发型TRIGGER_F
                              Condition:进墓地前在手卡+被丢弃
                              operation:发动效果的这张卡+表侧表示+特殊召唤+自己场上
                              Target:好像没有
                              试一下一伪代码的形式将上面的信息写成condition等函数的具体实现。
                              Function condition(e,tp,eg,ep,ev,re,r,rp)
                              return这张卡之前在手卡上and 事件原因是被丢弃
                              end
                              function Target(e,tp,eg,ep,ev,re,r,rp,chk)
                              if chk ==0 return true end ——我们目标对象就是这张卡,所以无论如何都可行。
                              ※设置operation的信息:宣言特殊召唤,这张卡,1张……——这一句可暂时不用理解
                              end
                              function operation(e,tp,eg,ep,ev,re,r,rp)
                              if 发动效果的是这张卡then 表侧表示特殊召唤到自己场上end
                              end
                              上面就把伪代码写好了,接着只要根据伪代码去function.txt找对应的函数替换掉中文部分就行了。其实正式的代码跟伪代码已经相差不大,不信你自己看。
                              function c82888408.spcon(e,tp,eg,ep,ev,re,r,rp)
                              return e:GetHandler():IsPreviousLocation(LOCATION_HAND) and bit.band(r,REASON_DISCARD)==REASON_DISCARD
                              end
                              function c82888408.sptg(e,tp,eg,ep,ev,re,r,rp,chk)
                              if chk==0 then return true end
                              Duel.SetOperationInfo(0,CATEGORY_SPECIAL_SUMMON,e:GetHandler(),1,0,0)
                              end
                              function c82888408.spop(e,tp,eg,ep,ev,re,r,rp)
                              if e:GetHandler():IsRelateToEffect(e) then
                              Duel.SpecialSummon(e:GetHandler(),0,tp,tp,false,false,POS_FACEUP)
                              end
                              end


                              27楼2014-07-24 10:32
                              回复