# 流星.net As脚本引擎  

## 版本 2.7.7

### 作者 滴风

## 介绍

As脚本引擎可以运行AngelScript脚本，旨在替换游戏内置的Pst脚本引擎，具有更高的性能和开发效率。

***

## 版本变动
+ 2.7.7
  + 修复 如果没有UserData/user_default.cfg, 按重置按钮无效 的问题

+ 2.7.6
  + 新增 图片UV变换功能
  + 新增 默认按键配置功能，可以先将 user.cfg 复制一份到 UserData/user_default.cfg，在游戏内点击重置按键按钮时，会读取该文件
  + 新增范例 
    + 设置共享变量，可以在任意时机、跨脚本调用
    + 图片UV变换功能
    + 模拟 OpenFile() ReadFile() WriteFile()，适用于自启动脚本

+ 2.7.5
  + 修复 在使用PST脚本的情况下，在威震八方小房间死亡后无法传送出去的问题

+ 2.7.4
  + 修复 无法读取某些PNG图片的问题

+ 2.7.3
  + 脚本DLL开发要求提高到 Visual Studio 2022 工具集

+ 2.7.2
  + 修复 执行 RemoveNPC() 后有几率导致稍后游戏崩溃的问题
  + 修复 在关卡结束时，由于存在PST的NPC，调用GetCharName会导致崩溃的问题
  + 新增API： 
    + bool IsTwoPointsVisible(Vector3 p1, Vector3 p2) 两点之间是否可见
  + 新增范例:
    + 判断两个角色之间是否互相可见


+ 2.7.0
  + 新增 API：
    + 凭空扔出和创建临时道具
      + void CharDropTempItem(int charId, int type, int itemId) 由指定角色凭空从自身扔出临时道具
      + void CharDropTempItem(int charId, int type, int itemId, Vector3 position, float angle) 由指定角色在某个位置朝某个方向凭空扔出临时道具
      + void CharCreateTempItem(int charId, int type, int itemId, Vector3 position) 由指定角色在某个位置创建一个临时道具
    + AddNPC 支持变量覆写
      + AddNPC("npc01_01", "Name=张三;HP=2000;") 在添加npc01_01之后，修改角色名称和HP
      + 变量覆盖的时机发生在OnInit(int this) 的末尾
    + AsCharAttack(int charId, string dirKeys) 更全面的模拟角色搓招, 支持任意角色和任意招式，支持跳跃和停顿0.2秒，取代 AsNpcAttack
      + 1号角色模拟按下 跳，停顿0.4秒，单A : AsCharAttack(1, "j,,n");
      + 2号角色模拟按下 单A，停顿0.5秒，前前A，停顿1秒，前前A : AsCharAttack(2, "n.ff..ff")
    + 新增 事件处理函数
      + void OnTempItemPickUp(int resItemType, int resItemId, int charId) 处理临时道具被捡起的事件
      + void OnCharacterKill(int killerId, int beKilledId) 处理角色击杀事件
      + void OnCharacterDeath(int charId, int reason) 处理角色死亡事件
      + void OnCharacterReborn(int charId) 处理角色复活事件
  + 新增范例:
    + 凭空扔出和创建临时道具
    + 处理以上事件
    + 模拟角色搓招

+ 2.6.2
  + 修复 CharGetBufferList 在某些情况下不准确的问题

+ 2.6.1
  + 修复 执行SetDisplayName后，在退回主菜单时崩溃的问题

+ 2.6.0
  + 新增 API:
    + int[] GetCharIdList() 获取当前角色ID列表
    + int GetActivePose(int charId) 获取指定角色当前的Pose
    + void SetTeam(int charId, int team) 修改指定角色的所属队伍
    + void SetDisplayName(int charId, string name) 修改指定角色的显示名称
    + string GetDisplayName(int charId) 获取指定角色的显示名称
    + bool IsAlive(int charId) 判断指定角色是否活着
    + int CharGetBaseAttrib(int charId, int type) 获取指定角色的基础属性
    + void CharSetBaseAttrib(int charId, int type, int value) 修改指定角色的基础属性
  + 新增范例：
    + 使用 GetCharIdList 和 GetActivePose ，在屏幕右上角显示各个角色当前的Pose
    + 修改角色的显示名称和所属队伍
    + 获取并修改角色的“基础属性”，包括 最大血量、当前血量、攻击力、防御力、速度
      + 注意， 角色 最终属性值 = 基础属性值 + 武器属性值 + Buffer属性值 + 其它
      + 你可以用修改基础属性值的功能来做角色养成的游戏玩法

+ 2.5.0
  + 修复 在拿着乾坤刀时调用 CharBaoQi 会闪退的问题

+ 2.4.0
  + 新增API:
    + int GetKill(int charId) 获取指定角色的击杀次数
    + int GetDead(int charId) 获取指定角色的死亡次数
    + void Reborn(int charId) 复活指定角色
  + AsSprite图片精灵:
    + 增加色调可选参数 Vector4 Tint
      + g_sprite.Tint = Vector4(1,1,1,0.5) 表示正常色调，但透明度为0.5
  + 新增媒体文件重定向函数:
    + 主要用于指定任务胜利动画，具体用法参考范例
  + 新增范例:
    + 将任务默认胜利动画修改为其他动画

+ 2.3.0
  + 新增API:
    + BufferDetail[] CharGetBufferList(int charId) 获取指定角色的Buffer列表
    + void CharRemoveBuffer(int charId, int resItemId) 移除指定角色的指定Buffer
  + 增加范例：
    + 遍历角色的Buffer列表
    + 判断角色是否有指定Buffer，并移除它
    + 移除指定角色的1个或多个Buffer


+ 2.2.0
  + 新增API：
    + void EnterScene(int sceneId)  进入指定单人任务
    + void ExitScene() 退出单人任务

+ 2.1.0
  + 修正API Rand 生成随机数的行为

+ 2.0.0
  + 新增道具API
    + int GetSceneItemId(string name) 根据道具名称获取道具Id
    + string GetSceneItemModelName(int id) 获取指定道具的模型名称
    + bool SetSceneItemPosition(int id, Vector3 position) 设置指定道具位置
    + Vector3 GetSceneItemPosition(int id) 获取指定道具位置
    + int GetSceneItemCount() 获取道具数量
    + int CreateSceneItem(string name, string typeName, string modelName) 创建道具
    + float GetSceneItemRotationYaw(int id) 获取指定道具水平朝向角度
    + bool SetSceneItemRotationYaw(int id, float angle)  设置指定道具水平朝向角度
  + 新增角色API
    + void CharSetRotationYaw(int charId, float angle) 设置指定角色水平朝向角度
    + float CharGetRotationYaw(int charId) 获取指定角色水平朝向角度
  + 新增地图API
    + Vector3 GetMapBoundingBoxSize() 获取地图包围盒大小
    + Vector3 GetMapBoundingBoxMin() 获取地图包围盒的最小点的位置
    + Vector3 GetMapBoundingBoxMax() 获取地图包围盒的最大点的位置
  + 支持大于(-3276, 3276)范围的超大地图
  + 支持用表格配置文件来创建宝藏
  + 添加 范例
    + 创建宝藏

+ 1.9.0
  + 修复VSCode无法编译带有图像补丁API的脚本的问题
  + 新增API
    + int GetAttack(int charId) 获取指定角色的攻击力
    + int GetDefense(int charId) 获取指定角色的防御力
    + int GetSpeed(int charId) 获取指定角色的移动速度
    + int CharBaoQi(int charId) 命令指定角色爆气
    + int CharJump(int charId) 命令指定角色跳跃
    + string GetGameVersionText() 获取游戏版本号文本
  + 控制台去掉快捷键CTRL+F1，仅保留波浪键~

+ 1.8.0
  + 修复API AsIsKeyPressed(int keyCode) 判断是否按下一次某个键盘按键，修复重复检测的问题
  + 新增API AsIsMouseClicked(int key) 判断是否点击一次鼠标键
    + AsIsMouseClicked(0) 判断是否点击一次鼠标左键
    + AsIsMouseClicked(1) 判断是否点击一次鼠标右键
    + AsIsMouseClicked(2) 判断是否点击一次鼠标中键
  + 新增API AsIsMouseDown(int key) 判断是否一直按住鼠标键
  + 新增API CharGetPosition CharGetRotation CharSetPosition CharSetRotation 角色位置和身体朝向相关的API
    + Vector3 position = CharGetPosition(2) 获取2号角色的位置
    + Vector3 rotation = CharGetRotation(2) 获取2号角色的身体朝向参数
    + Print(CharGetRotation(1)) 在控制台输出1号角色的身体朝向参数
    + Vector3 position = Vector3(100,200,300); CharSetPosition(2, position) 将2号角色瞬移到(100,200,300)这个位置
    + Vector3 rotation = Vector3(0.5,0.5,0); CharSetRotation(2, rotation); 将2号角色身体朝向参数调整为(0.5,0.5,0)
  + 新增API CharShowPose(int charId, int poseId) 角色展示特定pose，支持玩家和NPC，取代SetAggressPose 这个API
    + CharShowPose(1, 300) 1号角色展示pose300
  + API CharDropWeapon(int charId) 扔掉角色主武器，支持玩家和NPC
  + API CharSwitchWeapon(int charId) 带动画地切换角色主副武器，支持玩家和NPC
  + API Print 和 Output 支持输出任意类型
    + Print(3.145) 在控制台输出小数
    + Print(Vector3(100,200,300)) 在控制台输出三维向量

+ 1.7.0
  + 新增API AsImageCacheFolder(string path) 缓存指定文件夹内的图片
  + 新增API AsLoadImageFile(string filename) 读取缓存或硬盘的图片，优先读取缓存里的图片
  + 新增API double GetGlobalTime() 获得全局时间（从首次进入主菜单开始计算）
  + 新增API AsIsKeyDown(int key) 判断是否按住某个按键
  + 修复API AsGetGameWindowSize() 获取游戏窗口尺寸
  + 优化 AsSprite 图片精灵 优先从缓存里读取图片
  + 新增 Mod信息面板.as 可以在主菜单显示Mod作者信息
  + 现在可以在任意时机执行 Rand 函数
  + 优化 脚本引擎性能
  + 支持 加密脚本
  + 修复 热重载
  + 修复 其他BUG
  + 添加 范例
    + 缓存文件夹里的图片
    + AsIsKeyDown

+ 1.6.0
  + 新增API AsGetGameWindowSize() 获取游戏窗口尺寸
  + 添加 图片精灵模块 AsSprite，简化显示图片的步骤
    + 可以动态修改图片源、大小、位置、锚点、底色
    + 大小、位置、锚点，用的都是相对坐标，最小(0,0) ，最大 (1,1)
  + 添加 动作队列功能
    + 可以用来显示一段时间的图片
    + 可以用来做，让玩家按下按键来执行分支剧情的功能
    + API
      + AsActionQueuePushFunc(uint id, ActionFunc@ func, float duration = 0) 将代码块传入到指定队列里，然后顺序执行
      + AsActionQueuePushWait(uint id, float duration) 将等待行为传入到指定队列里，然后顺序执行
      + AsActionQueueSkip(uint id) 在指定队列中，跳过正在执行的行为
      + AsActionQueueSkip() 在当前队列中，跳过正在执行的行为
  + 添加 范例
    + 图片精灵
    + 动作队列
      + 显示一段时间的图片
      + 让玩家按下按键来执行分支剧情的功能

+ 1.5.0
  + 新增API GetScriptVarInt GetScriptVarString 获取脚本的全局变量值
  + 新增API ShowChatText(bool enable) 显示或隐藏聊天信息
  + 新增API GetGameTimeFloat() 获取高精度游戏时间，返回值为float类型
  + 新增API SetSharedVarInt SetSharedVarString GetSharedVarInt GetSharedVarString
  + 新增API ScanDir

  + AsHelper.as 新增API
    + AsSoundLoad(string trackName, string filename) 将wav文件载入到指定音轨
    + AsSoundPlay(string trackName, bool isLoop = false) 播放指定音轨，还可以设定是否循环播放
    + AsSoundPlay(string trackName, string filename, bool isLoop = false) 将wav文件载入到指定音轨，并播放指定音轨，还可以设定是否循环播放
    + AsSoundStop(string trackName) 停止播放指定音轨
    + AsSoundSetPosition(string trackName, float x, float y, float z) 将音轨放置到特定位置XYZ
    + AsSoundBindObject(string trackName, const string&in objectType, int objectId) 将音轨绑定到特定对象，并跟随对象
    + AsSoundUnBindObject(string trackName) 解绑音轨
    + AsSoundCacheFolder(string folerName) 将指定文件夹内的所有wav文件缓存到内存，可以避免之后由于临时读取而导致卡顿的现象
    + AsSetChatVoiceFolder(string folderName) 设定角色语音文件夹
    + AsPerform 代替 Perform，并且有角色语音功能
    + AsPlayerPerform 代替 PlayerPerform，并且有角色语音功能
    + AsSay 代替 Say，并且有角色语音功能
  + GetCharName(int id) 如果输入的是主角的编号，则返回 player
  + 支持 在控制台里输入 AsHelper.as 的API
  + 添加 声音相关的范例
  + 修复 在某些罕见情况下严重卡顿的问题
  + 修复 若干BUG

+ 1.4.0
  + 新增API SetKeyCommandHint SetKeyEscHint 修改\和Esc的按键提示
    + \键有文字提示: SetKeyCommandHint("已打开 \\ 键 功能", "已禁用 \\ 键 功能", "\\ 键被锁定")
    + \键无文字提示: SetKeyCommandHint("", "", "")
    + Esc键有文字提示: SetKeyEscHint("已打开 Esc 键 功能", "已禁用 Esc 键 功能", "Esc 键被锁定")
    + Esc键无文字提示: SetKeyEscHint("", "", "")
  + 新增API CharSwitchWeapon SetAllowCharSwitchWeapon IsAllowCharSwitchWeapon NPC切换主副武器相关
    + 禁止2号NPC切换武器: SetAllowCharSwitchWeapon(2, false)
    + 允许2号NPC切换武器: SetAllowCharSwitchWeapon(2, true)
    + 检查是否允许2号NPC切换武器: if (IsAllowCharSwitchWeapon(2)) { ... }
    + 命令2号NPC切换武器(不受SetAllowCharSwitchWeapon影响): CharSwitchWeapon(2)
    + 命令2号NPC切换武器(受SetAllowCharSwitchWeapon影响): CharSwitchWeapon(2, false)
  + 新增API CharDropWeapon CharDropVipItem NPC扔掉身上的主武器和镖物
    + 命令2号NPC扔掉主武器: CharDropWeapon(2)
    + 命令2号NPC扔掉镖物: CharDropVipItem(2)
  + 可以通过读取存档的方式来设置任务和NPC的基础全局变量
  + AsNpcAttack NPC模拟搓招支持单A
    + 2号NPC模拟按下 单A，停顿0.5秒，前前A，停顿1秒，前前A : AsNpcAttack(2, "n.ff..ff")
  + 修复若干BUG
  + 添加范例：
    + 修改\和Esc的按键提示
    + NPC切换主副武器
    + NPC扔武器和镖物
    + 以读取存档的方式设定任务基础全局变量
    + 以读取存档的方式设定NPC基础全局变量
    + 任务脚本里调用场景脚本里的函数
    + 任务脚本里调用NPC脚本里的函数
    + 脚本语法基础

+ 1.3.1
  + 修复 如果As脚本编写错误会导致游戏崩溃的问题

+ 1.3.0
  + 进入游戏后，会自动切换到英文输入法
  + 按波浪键~(在数字1左边)呼叫控制台
  + 新增API PlayMusic(string filename) 切换背景音乐
    + 播放s2.mp3: PlayMusic("music/s2.mp3")
  + 新增API EnableKeyCommand(bool enable) 锁定或解锁“\”键
    + 锁定“\”: EnableKeyCommand(false)
    + 解锁“\”: EnableKeyCommand(true)
  + 新增API EnableKeyEsc(bool enable) 锁定或解锁“Esc”键
    + 锁定“Esc”: EnableKeyEsc(false)
    + 解锁“Esc”: EnableKeyEsc(true)
  + 新增API PrintSystemText(string text) 在屏幕右方输出文字
  + 新增API SetAggressPose(int charId, int poseId) 给NPC指定挑衅Pose
  + 新增助手脚本 AsHelper.as，封装了不少函数，大幅降低使用难度，范例.as 内有详细用法
    + 可以通过在你的脚本里加上 #include "../PScriptLib/AsHelper.as" 获得以下功能：
    + AsIsKeyPressed(int keyCode) 判断是否按下一次某个按键
    + AsSwitchWeapon(int weaponId) 切换武器
    + AsPlayerPose(int poseId) 玩家做出指定Pose
    + AsMoveTo(float x, float y, float z) 玩家瞬移到指定位置
    + AsMoveToChar(int charId) 玩家瞬移到指定Npc
    + AsMoveToWayPoint(int waypointId) 玩家瞬移到指定路点
    + AsMoveToFlag(int flagId) 玩家瞬移到指定镖物
    + AsMoveToDoor(int doorId) 玩家瞬移到指定门
    + AsMoveToSafe(int safeId) 玩家瞬移到指定出口
    + AsSwitchPlayerSkin(string skinName) 切换玩家皮肤
    + AsSaveStats(string name, int[] stats, bool encrypt) 保存存档，支持加密
    + AsLoadStats(string name, bool encrypt, int[]&inout outStats) 读取存档，支持
    加密
    + AsNpcAttack(int charId, string dirKeys) NPC模拟按下搓招键
      + 2号NPC模拟按下 ↑A，停顿1秒，↑↑A，停顿1.5秒，↓↓↑A : AsNpcAttack(2, "f..ff...bbf");
      + 3号NPC模拟按下 ←→↑↓ A : AsNpcAttack(3, "lrfb")

+ 1.2.0
  + 修复API UpdateAIAttrib(charId)无效的问题
  + 示例“图片测试”增加层叠功能
  + 修复 娱乐菜单的瞬移功能

+ 1.1.0
  + 新增API Command(...)，可以用来执行隐藏命令，例如瞬移moveto，更换皮肤loadmych, 更换武器weapon
  + 新增API GetPosition(int targetIndex), 可以用来获取目标位置，配合SetTarget(...)使用
  + 新增API GetWeapon2 GetWeaponType2，分别是获取副武器的ID和类型
  + 修复API GameOver
  + 修复API GetChar GetAnyChar，这两个API最多支持输入2个参数
  + 支持 Scene_OnCharacterEvent 事件
  + 从游戏版本1.07到9.08都可以使用 GetAnger GetWeapon GetWeaponType
  + 控制台支持输入中文
  + 修复 载入Reshade后 会崩溃的问题
  + 修复 字体缩放
  + 进入游戏主菜单后才调用脚本的OnUpdate方法，避免图形界面显示在开场动画之上
  + 娱乐菜单添加瞬移、换皮肤、换武器功能

***

## 特点  

+ 支持 bool float uint string 动态数组

+ 完整支持C语言各种语法，如 for while switch

+ 无需运行游戏即可检查语法错误

+ 仅需极少量的修改，即可从Pst脚本迁移到As脚本

+ 可在任务脚本里调用场景API

+ 可在任务脚本里接收场景事件

+ 支持自启动脚本，进入游戏后自动运行，适用于全局执行，支持接收所有游戏事件和调用所有游戏API

+ 更全面的脚本API，包括字符串操作、动态数组操作、字段操作、图形界面操作、文件操作

+ 自动热重载，在游戏运行时，如果检测到脚本文件被修改，就会自动重新加载到游戏，并尽可能还原所有变量值

+ 可以在游戏内实时调用脚本API

+ 可加载由第三方制作的脚本DLL，可用来增加额外的脚本API

+ 解除任务人数和阵营人数限制，所有NPC都能动

***

## 截图

![avatar](截图/控制台和娱乐菜单.jpg)

***

## 目录结构  

``` tree
游戏目录
├─AsScripts                       # 存放 脚本
│  ├─.vscode                      # vscode 的配置目录
│  ├─Level                        # 存放 任务和NPC脚本
│  ├─PScriptLib                   # 存放 共享的脚本
│  ├─sn01                         # 存放 钟乳洞的场景脚本
│  └─Startup                      # 存放 自启动脚本
└─UserData                        # 存放 用户数据，可以是图片，文本txt，表格csv
    ├─Engine                      # 存放 引擎文件
    ├─Saves                       # 存放 存档
    └─ScriptDlls                  # 存放 第三方脚本DLL
```

***

## 支持的游戏版本

+ 1.07.16
+ 9.07.16
+ 1.08.1
+ 9.08.1
+ 1.08.3

***

## As脚本引擎安装方法

+ 将压缩包里的主文件里面的所有文件和文件夹，拖到游戏文件夹内并覆盖
+ 运行其他工具文件夹里的Hxd.exe
+ 把游戏执行文件Meteor.exe 拖进去
+ CTRL+R 打开替换窗口
+ 在搜索框填入 ADVAPI32.dll
+ 在替换框填入 AsEngine.dll
+ 选举类型选 字符串
+ 搜索方向选 全部
+ 取消选择 通用国际字符集字符串
+ 取消选择 大小写敏感
+ 点击全部替换， 会显示替换了1次
+ 保存

***

## 脚本安装方法

+ 对于任务脚本，把 snxx_.as 放到 AsScripts\\Level 内
+ 对于场景脚本，把 snxx.as 放到 AsScripts\\snxx 内
+ 对于NPC脚本，把 npcxxxx.as 放到 AsScripts\\Level 内
+ 对于自启动脚本，把 xxxx.as 放到 AsScripts\\Startup 内

载入任务、场景、NPC时，如果 AsScripts 内有对应的As脚本，会加载As脚本，否则会加载游戏自带的Pst脚本

***

## 常见问题

+ 为什么调用 OpenFile ReadFile WriteFile CloseFile 时，老提示错误？
  + 这几个游戏API是游戏1.08版本或以上才有的，要用刚才提到的exe才可以使用  
+ 为什么不能显示图形界面？
  + 需要安装图像增强补丁才能显示图形界面
+ 为什么调用 Command(...) 无效？
  + 需要使用其他工具打开游戏的隐藏命令功能，比如这个工具[流星隐藏命令开启器v2.0(通用版)](https://www.lxres.com/BuDingGongJu/ShiYongGongJu/9.html)
+ 任务脚本的OnUpdate()函数，每秒运行多少次？
  + 每帧运行一次，意味着你不能用计数方法来计算游戏运行时间，请用GetGameTime()来获取游戏时间

***

## 脚本模板  

位于脚本模板文件夹内，可通过复制一份之后，删减里面的内容来制作属于自己的As脚本

+ 自启动脚本模板.as
+ 任务脚本模板.as
+ 场景脚本模板.as
+ NPC脚本模板.as

***

## 示例脚本

以下脚本在 主文件\AsScripts\Startup\
可以按需删除

+ 控制台.as 和 Console文件夹
    可实时输入并调用API，输出调试信息，对于开发脚本非常有用，按CTRL+F1切换显示窗口
+ 娱乐菜单.as  
    实现菜单功能，支持多级菜单和翻页功能，在场景内按J键切换显示  
    内含存档操作、动态数组操作、字典操作、回调函数操作、图形界面操作、跨脚本调用操作
+ 图片测试.as  
    演示在图形界面里显示图片的功能
+ 小键盘切换武器  
    可以用键盘右边的小键盘数字键来切换武器

***

## 自带脚本

+ Level\\sn01_.as  
    一个从Pst转换到As的任务脚本
+ sn01\\sn01.as  
    一个从Pst转换到As的场景脚本
+ Level\\npc01_*.as  
    多个从Pst转换到As的NPC脚本
+ PScriptLib\\*.as  
    多个从Pst转换到As的共享脚本文件

***

## 访问权限控制

由于考虑到安全性问题，因此作出以下限制：

+ 可读取 游戏目录内的所有文件
+ 可写入 游戏目录\UserData\Saves\
+ 对于单个脚本模块，最大可写入1 MB的文件，这对于存档来说足够用了

***

## 脚本事件

### 启动游戏时

+ 载入AsScripts\\Startup文件夹内的所有脚本
+ 自启动脚本  
  + OnStart()

### 进入场景时，战局开始前

+ 检查是否有AsScripts\snXX\snXX.as场景脚本文件
+ 如果有，则载入As脚本，否则，载入Pst脚本
+ 场景脚本  
  + Scene_OnLoad()  
  + Item_OnLoad(int id)  

### 进入任务时，战局开始前

+ 检查是否有AsScripts\Level\snXX_.as场景脚本文件
+ 如果有，则载入As脚本，否则，载入Pst脚本
+ 任务脚本  
  + OnInit();

### 开始战局时

+ 场景脚本  
  + Scene_OnInit()  
  + Item_OnInit(int id)  
+ 任务脚本  
  + OnStart()  
  + Item_OnInit(int id)  
+ 自启动脚本  
  + Level_OnStart()
  + Scene_OnInit()
  + Item_OnInit(int id)  

### 道具被接触时

+ 场景脚本  
  + Item_OnTouch(int id, int characterId);  
+ 任务脚本  
  + Item_OnTouch(int id, int characterId);  
+ 自启动脚本  
  + Item_OnTouch(int id, int characterId);  

### 道具被攻击时

+ 场景脚本  
  + Item_OnAttack(int id, int characterId, int damage);  
+ 任务脚本  
  + Item_OnAttack(int id, int characterId, int damage);  
+ 自启动脚本  
  + Item_OnAttack(int id, int characterId, int damage);  

### 道具被捡起时

+ 场景脚本  
  + Item_OnPickUp(int id, int characterId);  
+ 任务脚本  
  + Item_OnPickUp(int id, int characterId);  
+ 自启动脚本  
  + Item_OnPickUp(int id, int characterId);  

### NPC进入场景时

+ NPC脚本
  + OnInit(int This);
  + OnStart();
+ 自启动脚本
  + NPC_OnStart(int npcId);

### 游戏更新时

+ 场景脚本  
  + Scene_OnIdle()  
  + Item_OnIdle(int id)  
+ 任务脚本  
  + OnUpdate()
  + Item_OnIdle(int id)  
+ NPC脚本  
  + OnUpdate()  
+ 自启动脚本  
  + OnUpdate()  
  + Item_OnIdle(int id)  

### 场景结束时

+ 场景脚本  
  + Scene_OnStop()  
+ 自启动脚本  
  + Scene_OnStop()  

### 场景内角色死亡或重生时

+ 场景脚本
  + Scene_OnCharacterEvent(int characterId, int event)
+ 任务脚本
  + Scene_OnCharacterEvent(int characterId, int event)
+ 自启动脚本
  + Scene_OnCharacterEvent(int characterId, int event)

### 任务结束时

+ 任务脚本  
  + OnStop()  
+ 自启动脚本  
  + Level_OnStop()  

### 退出游戏时  

+ 自启动脚本  
  + OnStop()  

### 脚本文件被修改后且成功热重载时

+ 自启动脚本
  + OnStop()
  + OnStart()

***

## 脚本API

### 所有API声明都在  AsScripts/Api.h 里，可以用VSCode打开查看

### 分类

+ 游戏API  
  + 游戏内置的API  
  功能跟游戏内置的一模一样，这里不作介绍  
  <https://www.lxres.com/LiuXingBiJi/1563.html>
+ 实用API
  + string 字符串  
  <https://urho3d.io/documentation/HEAD/class_urho3_d_1_1_string.html>
  + array 动态数组  
  <https://www.angelcode.com/angelscript/sdk/docs/manual/doc_datatypes_arrays.html>  
  实际上跟文档里的有点区别，方法首字母全部改成大写
  + dictionary 字典  
  <https://www.angelcode.com/angelscript/sdk/docs/manual/doc_datatypes_dictionary.html>
  + ImGui 图形界面
  <>
  + File 文件  
  <https://urho3d.io/documentation/HEAD/class_urho3_d_1_1_file.html>
  <https://urho3d.io/documentation/HEAD/class_urho3_d_1_1_deserializer.html>
  <https://urho3d.io/documentation/HEAD/class_urho3_d_1_1_serializer.html>
  + Color 颜色  
  <https://urho3d.io/documentation/HEAD/class_urho3_d_1_1_color.html>
  + Image 图像  
  <https://urho3d.io/documentation/HEAD/class_urho3_d_1_1_image.html>
  + Vector2 IntVector2 二维向量  
  <https://urho3d.io/documentation/HEAD/class_urho3_d_1_1_vector2.html>
  <https://urho3d.io/documentation/HEAD/class_urho3_d_1_1_int_vector2.html>
  + Vector3 IntVector3 三维向量  
  <https://urho3d.io/documentation/HEAD/class_urho3_d_1_1_vector3.html>
  <https://urho3d.io/documentation/HEAD/class_urho3_d_1_1_int_vector3.html>
  + Vector4 IntVector4 四维向量  
    <https://urho3d.io/documentation/HEAD/class_urho3_d_1_1_vector4.html>
  
+ 新增API

</pre>

```c
// 返回场景道具名称
string GetSceneItemName(int itemId);
// 执行单行脚本
bool ExecuteLine(const string & cmd);
// 载入图片，并返回图片句柄
Image@ LoadImageFile(const string &);
// 显示鼠标
void ShowMouse();
// 跨脚本执行函数
bool ExecuteFunction(int scriptId, const string& functionName, arg1, arg2, ...);
// 跨脚本执行函数
bool ExecuteFunction(const string& scriptName, const string& functionName, arg1, arg2, ...);
// 返回任务脚本Id
int GetLevelScriptId();
// 返回任务脚本的文件名
string GetLevelScriptName();
// 返回Npc脚本的Id
int GetNpcScriptId(int npcId);
// 返回Npc脚本的文件名
string GetNpcScriptName(int scriptId);
// 返回场景脚本Id
int GetSceneScriptId();
// 返回场景脚本文件名
string GetSceneScriptName();
// 禁止执行单行脚本，禁止之后，直到游戏重新启动才解除禁止
void DisableExecuteLine();
// 执行游戏指令，就是按\键输入的那些命令， 参考 https://www.lxres.com/LiuXingBiJi/1551.html
void Command(const string&in cmd, const string&in arg1, ...);
// 获取目标位置, 配合 SetTarget(targetIndex, ...) 使用
Vector3 GetPosition(int targetIndex);
// 获取副武器的ID
int GetWeapon2(int characterId);
// 获取副武器的类型
int GetWeaponType2(int characterId);
// 切换背景音乐
bool PlayMusic(string filename);
// 解锁/锁定 "\" 键
void EnableKeyCommand(bool enable);
// 解锁/锁定 "Esc" 键
void EnableKeyEsc(bool enable);
```

***

## 从 Pst脚本 迁移（转换）到 As脚本

+ 数组

    ```c
    // Pst写法
    int g_shuzu[100];  
    // As写法
    int[] g_shuzhu(100) ;
    // 或
    array<int> g_shuzhu(100); 
    ```

+ 函数体

    ```c
    // Pst写法
    OnStart()
    {
        int a = 0
        if (a == 0)
        {
            return 0;
        }
    }
    // As写法， 函数声明前面需要加上返回值类型
    int OnStart()
    {
        int a = 0
        if (a == 0)
        {
            return 0;
        }
        return 1;
    }
    ```

+ 特殊游戏API

    ```c
    // Pst写法
    rand(1);
    // As写法
    Rand(1);
    ```

+ 字符串内的文件路径

    ```c
    // Pst 写法
    "UserData\Saves\npctest.sav"
    // As 写法
    "UserData/Saves/npctest.sav"
    ```

***

## 脚本开发环境

安装 [VSCode](https://code.visualstudio.com/) 之后，再从扩展商店里安装以下扩展

+ AngelScript 作者 René Sackers  
提供As代码高亮显示的功能  
+ Output Colorizer 作者 IBM  
提供输出窗口文本的高亮显示功能
+ Run on Save 作者 emeraldwalk  
提供按保存键时执行特定任务的功能

具体操作

+ 打开 VSCode ，并打开文件夹 “游戏目录\AsScripts”
+ 编辑该文件夹内的任意一个文件，按Ctrl+S或者保存键
+ 此时会自动调用游戏目录下的ScriptCompiler进行编译，编译结果会输出到Run On Save窗口里，可以 CTRL+单击 窗口里的行信息来定位出错位置
![avatar](截图/run_on_save.png)

***

## 脚本DLL开发

可自行查阅 ScriptDllSample  

+ 需要 Visual Studio 2022 或以上版本(平台工具集 v143...)
+ 如果调试期间意外崩溃，请尝试切换到Release模式下并关闭优化来编译调试
