jass 笔记

| 发布     | 分类 war3  | 标签 jass  war3 

相关连接

http://war3.uuu9.com/war3rpg/List_477.shtml

一:介绍

  • jass脚本定义为一系列 *.ai 和*.j文件, 这些文件允许触发器脚本或AI脚本
  • 地图脚本:common.j, Blizzard.j, war3map.j (按顺序加载)
  • AI脚本: common.j, common.ai, 用户自定义AI脚本(human.ia等)
  • common.j, Blizzard.j, common.ai 在MPQ中 (Scripts目录中)
  • war3map.j 放在*.w3m地图文件中

二: 语法

2.1 类型定义

type new_type extends parent_type

2.1.1 基础类型

Type 类型  
integer 整数 32 位, -2147483647 到 2147483647
real 实数(即浮点数或小数) 32 位,并符合 IEEE 标准 754 浮点标准
boolean 布尔 true, false
string 字符串 空值可以用 null
handle 句柄,结构体引用 基本上是一个”指针”。
指一些数据结构
从句柄继承的所有用户定义的类型。
例如,是指向游戏中某些单位数据结构的子类型。可以为任何句柄变量分配值,这意味着它引用任何。
code 函数引用 函数引用作为参数,似于 C 或 C++ 中的函数指针
function RunFunctionForAllPlayers takes code theFunction returns nothing
array 数组  

2.1.2 在Jass中Integer的几中特殊形式:

  • 十进制: 任意数字, 负数、0、正数, 如: 12, -1999, 9999
  • 八进制: 首位为0表示8进制数字, 如012等于10
  • 十六进制: 以 0x 开头, 例如:0x2=2,0xA= 10,0x10 = 16,0xFF =255 。
  • 字符: ‘xxxx’ 单引号加字符形式,该形式为256进制整数,每个字符代表其AscII码值,区分大小写,一般用来表示单位、物品、技能等代码。比如对战单位里剑圣的代码是 ‘Obla’
  • 4 个字符. -整数使用的 4 个字节的 ASCII 中的表示形式,此表示形式主要用于单位/技能/地形片tile/科技/等id。示例:”Aloc”,”B000”

2.1.3 string

string是字符串变量, 可以是null(空值). 注意Jass的字符串是大小写区分的, 赋值时用双引号 “” 引用

  • 空值表示方式 null 和 “”

转义

  • \n\r 回车符
  • \“ 引号
  • \\ 转义斜杠

格式

  • ** cAARRGGBB** 文本颜色, AA是alpha, RR是红色,GG是绿色,BB是蓝色, 用十六进制值。如 ffCC1100
  • ** r** 将文本颜色重置为正常
  • ** n** 新行,相当于回车符

    如:

    |cffff0000技能名称|r (|cffffcc00二级|r) |n 技能描述
    
技能名称 (二级)
技能描述

2.1.4 array

  • 指一组同类型的有序列的变量. 数组中包含的元素可以用[n]来指明(n 表示第n + 1个元素, 从 0 算起).

  • 以上所说的变量类型中除了code类型, 其他类型的变量都可以定义数组变量

  • 数组所有元素初始值是”空”, 比如integer类型的数组初始值为0, handle类型初始值的为null

  • 数组不能直接再次初始化, 只能数组按元素赋值

  • 数组在函数间不能互相传递. 即是不能把数组作为函数参数, 而且函数也不能返回数组类型的变量.

  • 数组元素域在 0 和JASS_MAX_ARRAY_SIZE = 8192 之间, 即是最多有JASS_MAX_ARRAY_SIZE + 1 个元素. JASS_MAX_ARRAY_SIZE是在common.j中定义的常数

    	locate integer array dropitems
    	set dropitems[0] = 'Xxxx'
    	......
      
     set dropitems[18] = 'Xbbb' // dropitems[18]指dropitems中第19个变量.
    

    数组不能直接再次初始化, 只能数组按元素赋值, 如:

     locate string array playername = "Greedwind" //数组非法赋值
     locate string array playername //数组元素只能逐个赋值
     set playername[1] = "Greedwind"
     set playername[2] = "Greedwind's girlfriend"
    
     unit array myUnits
     unit array yourUnits
    
      set myUnits = yourUnits // 非法
      set myUnits[0] = yourUnits[10] // 合法
    

2.1.5 WORLD EDITOR和JASS变量类型对照表:

World Editor 变量名 Jass变量类型
Boolean boolean 布尔型(用于真/假判断)
Destructible destructable 可破坏物
Dialog dialog 对话
Dialog Button button 按钮
Floating Text texttag 漂浮文字
Integer integer 数值
Item item 物品
Leaderboard leaderboard 排行榜
Player player 玩家
Player Group force 玩家组
Point location 位置(点)
Real real 真值型数字
Region rect 地区
Special Effect effect 特效
String string 字符串
Terrain Deformation terraindeformation 地形
Timer timer 计时器
Timer Window timerdialog 计时器窗口
Unit unit 单位
Unit Group group 单位组
Player Score playerscore 积分(1.13版新类型)

2.2 变量

2.2.1 全局变量

  • 声明都在封闭的globals … endglobals块中
  • 每个文件只能有一个全局块
  • 每个声明都单独一行
  • 变量类型:可以是基本类型,也可以是基本类型的数组
  • 变量声明的时候值可选
  • 常量声明前面加constant,不能用于数组
globals
	type name = expression
	type name = expression
	type name = expression
    ...
endglobals

例如,下面是一个整数变量,初始化为值 10:

	integer num = 10

初始化为另外两个变量的量值的常数整数变量:

     constant integer howManyUnits = numberOfGrunts * numberOfAttacks

未初始化的字符串变量:

  	string someMessage

单位数组。无法初始化数组。

     unit array listOfUnits

2.2.2 局部变量

  • 局部变量只能声明在函数里
  • 必须声明在函数开头,函数中间逻辑声明会报错

声明格式

local type name = expression

实例

function IntAdd takes integer a, integer b returns integer
	local integer result = a + b
	return result
endfunction


function Trig_ZFLearn02TrigerActions takes nothing returns nothing
	// 必须声明在开头
    local integer aa = 10
    local integer bb = 20
    local integer r
    
    call YDWEDisplayChat( Player(0), 0, udg_zfChatMsg )
    call YDWEDisplayChat( Player(0), 0, zfName )

    call YDWEDisplayChat( Player(0), 0, "add before: aa=" + I2S(aa)  + ", bb=" + I2S(bb))
    set r = ZF_TestFunBase(aa, bb)
    
    //local integer rr = r // 这里声明会报错
    
    call YDWEDisplayChat( Player(0), 0, "add after: aa=" + I2S(aa)  + ", bb=" + I2S(bb) + ", result=" + I2S(r))

    
endfunction

2.2.3 set: 给变量赋值,必须加set

function IntAdd takes integer a, integer b returns integer
	local integer result = a + b
	set a = a + a // 可以
	b = b + b // 错误
	set a += a // 错误
	return result
endfunction

2.2.4 数组


    local integer array numArr
    set numArr[0] = 1
    set numArr[1] = 2
    set numArr[3] = 3

    
    call YDWEDisplayChat( Player(0), 0, I2S(numArr[3]) )

2.3 内置函数 native function

  • 魔兽 III 引擎中实现的功能, 导出给 JASS 程序员的 API

  • 除非您有权访问魔兽III的源代码,否则您可能不会定义新的内置函数,但可能会调用它们

  • 他们声明在 common.j, common.ai, Blizzard.j

声明格式:

  native func_name takes param_list returns return_type

实例:

  native MakeUnitTalk takes string whatToSay, unit targetUnit returns nothing

2.4 自定义函数

  • 函数也可以声明为前缀。constant
  • 定义函数的关键字有: functionendfunction, takes, returns
  • 函数名的首个字母不能是数字, 函数名中不能有操作符, 特殊字符和多数非字母符号(如: 空格[~`!@#$%^&*()-+= {}];:’”<>?,./), 也不能使用中文. 函数命名要尽量简明易懂, 突出函数功能.
  • 参数表是规定传递入函数的数据类型和参数数量, 作用是函数间的数据交换(输入), 参数之间用逗号( , )分开. 不能定义数组作为参数
  • 调没有返回值的函数前面一定要加 call funanme(arg)

声明格式:

function func_name takes param_list returns return_type
     variable_declaration
     variable_declaration
     ...
     statement
     statement
     statement
     ...
endfunction

声明 无参数无返回值的函数, 如

// 声明函数
function myfunction1 takes nothing returns nothing

endfunction

// 调用函数
call myfunction1() // myfunction1为无参数的函数, 调用时不需要传递参数, 即是用

声明 多个参数用逗号分隔

// 声明函数
function myfunction2 takes integer creatnum, unit myunit returns boolean

  call CreateNUnitsAtLoc(creatnum, GetUnitTypeId(myunit), Player(1),

  GetUnitLoc(GetTriggeringUnit()), bj_UNIT_FACING )

  return true

endfunction

// 调用
local boolean isOk = myfunction2(1, myUnit)
set isOk = myfunction2(2, myUnit)

如果函数声明的前缀为 ,如下所示:constant

请注意,您仍然可以使用正文中的语句来更改函数参数,因此在典型意义上,它不是真正的”常数”;它更像是对程序员的暗示

constant function const_func takes integer a returns nothing
     ...
endfunction

2.4.1 回调函数 用法

  • 声明参数类型用 code
  • 传递参数时需要加 function
globals
    integer zfTimeIndex = 0
    timer zfTimer
endglobals


function ZF_TimeOnTick takes nothing returns nothing
    set zfTimeIndex = zfTimeIndex + 1
    call YDWEDisplayChat( Player(0), 0, "zfTimeIndex=" + I2S(zfTimeIndex) )

    if zfTimeIndex >= 5 then
        call DestroyTimer(zfTimer)
        set zfTimer = null
    endif
endfunction

function ZF_TimeStart takes code tickHandlerFun  returns nothing //  声明参数类型 code
    set zfTimer = CreateTimer()
    set zfTimeIndex = 0
    
    call TimerStart(zfTimer, 2.0, true, tickHandlerFun)
endfunction

function Trig_ZFLearn02TrigerActions takes nothing returns nothing
	call ZF_TimeStart(function ZF_TimeOnTick) // 传递参数时需要加 `function`
endfunction

2.5 程序执行入口函数

  • 每个Jass脚本文件都需要定义执行程序的入口函数
  • 在触发器脚本文件war3map.j中, config()main()是入口函数.
  • config()函数作用是在开始游戏之前初始化地图, 如按设计时指定点放置单位/可破坏物,初始化单位状态等.
  • main()函数在游戏开始才执行
  • 在AI脚本文件中, 用户需自定义main()函数作为该脚本文件的程序入口.
  • 注意: 一张地图中只能有1个触发器脚本文件war3map.j, 此文件包含在w3m或w3x中
  • 注意: 一张地图中可以包含多个AI脚本文件, 输入AI脚本文件的目录为: \scripts\

脚本文件执行入口函数的固定格式:

  function main takes nothing returns nothing //触发器和AI脚本均使用

  function config takes nothing returns nothing //触发器脚本使用

2.6 条件判断 if… elseif…else…endif

语法
if predicate then
    statement
    statement
    ...
elseif predicate then
    statement
    statement
    ...
elseif predicate then
	...
else
    statement
    statement
    ...
endif
实例
function ZF_Compare takes integer a, integer b returns integer
    local string strA = I2S(a)
    local string strB = I2S(b)
    if a == b then
        call YDWEDisplayChat( Player(0), 0, strA + " == " + strB )
        return 0
    elseif a > b then
        call YDWEDisplayChat( Player(0), 0, strA + " > " + strB )
        return -1
    else
        call YDWEDisplayChat( Player(0), 0, strA + " < " + strB )
        return 1
    endif
endfunction

2.7 循环 loop … endloop

语法

loop
    ...
    exitwhen expression
    ...
endloop

实例

local integer iterations = 10
loop
    if DidTheThingEnoughTimes() then
        call DisplayText("Exiting Early")
        exitwhen true
    endif
    call DoSomething()
    set iterations = iterations - 1
    exitwhen iterations == 0
endloop

function ZF_TestLoop takes nothing returns nothing
    local integer i = 0
    call YDWEDisplayChat( Player(0), 0, "循环开始 i=" + I2S(i) )
    loop
        call YDWEDisplayChat( Player(0), 0, "i=" + I2S(i) )
        set i = i + 1
        exitwhen i >= 10
    endloop
    call YDWEDisplayChat( Player(0), 0, "循环结束 i=" + I2S(i) )
endfunction

2.8 运算符

数学计算:

+
-
*
/

比较符号:

> 大于
< 小于
>= 大于等于
<= 小于等于
== 等于
!= 不等于

布尔条件

and 条件 且
or 条件 或
not 条件 否

字符串拼接

+ 连接字符串, 比如: local string a = “ZF” + “_” + “大海明月”
   

2.9 注释用双斜杠

// 注释
local string name = "zf" //声明本地变量

三:问答

3.1 什么是common.j, Blizzard.j, common.ai

  • common.j 是最基础的API库文件, 在Trigger Jass和AI Jass中都可以调用.
  • Blizzard.j 包含使用Trigger Editor时生成的Trigger Jass中经常调用的库函数/全局变量, 实际上是基于common.j写的子函数. Blizzard.j只能在Trigger Jass中调用.
  • common.ai 只能在AI Jass中调用, 它有AI中需要使用的函数和全局变量.

3.2 如何获得最新的common.j, Blizzard.j, common.ai?

在war3.mpq/war3x.mpq/war3patch.mpq都有common.j/Blizzard.j/common.ai, 要获得最新版本的文件, 可以用WINMPQ打开war3patch.mpq, 在WINMPQ右上方的输入框中输入: scripts* ,如果你的war3patch.mpq没有”加密”过, 那么可以找到这3个文件. 如果是”加密”过的, 则需要把war3patch.mpq的文件全部解压到临时目录, 然后用Ultra-Edit中的在文件中搜索字符的功能寻找这3个文件.

3.3 可以在自己的地图中使用自定义的common.j, Blizzard.j, common.ai吗?

可以. 用输入管理器输入自定义的common.j, Blizzard.j, common.ai, 输入目录应为\scripts. 这样, 运行地图中的脚本时, War3就不会到war3patch.mpq寻找这3个文件了而直接从地图中的\scripts\目录调用. 这样做的好处就是可以使库文件的同步一致. 通常, 版本相同的WAR3, 其库文件也相同, 所以多数时候不需要在地图中输入这3个文件. 但如果你更改了这3个基本文件来支持你的Jass, 或者确保为了库文件的一致性, 便可以在地图中输入基础库文件.

3.4 实用问题: 如何创建外观随机可变的地图?

上面说过, main()是地图入口函数, 在main()调用了一些再现地图设计时原貌的子函数如CreateAllUnits(). 因此, 我们可以在CreateAllUnits()中加入随机函数GetRandomInt()来控制单位/物品/可破坏物等初始化过程.

  我们可以用WINMPQ打开要修改的地图, 提取war3map.j来修改main()函数及其相关函数. 修改完war3map.j后, 再用WINMPQ导入修改后的war3map.j.

3.5 总结下Blizzard函数名/全局变量名的规律:

前坠/相关词 介绍
前坠 Get 取得某属性, 此类函数一般有返回值
前坠 Set 设置某属性
前缀 Create 创建
前缀 Remove 移除
前坠 Is 是否判断, 此类函数返回类型都是boolean, 返回true或false
前缀 bj_ 在Blizzard.j中定义声明的全局常量(常量是指定义并赋值后不能再改变的值)
后缀 BJ 此函数肯定是在Blizzard.j中定义的, 不能在AI中使用.
中间有 2 数据类型转化函数 如S2I(), I2R, I2S()等
有 Item/Unit/… 肯定是与物品/单位/…相关的函数
全部大写 在common.j中定义声明的全局常量
上一篇: 【笔记】LOL图形管线之旅读后感
下一篇: War3 触发器