diff --git a/_docs/api.md b/_docs/api.md index 3b5ce9d5..8c372139 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -780,6 +780,9 @@ getEnemys: fn() 获得所有怪物原始数据的一个副本。 请使用core.material.enemys获得当前各项怪物属性。 +getEnemyValue: fn(enemy?: string|enemy, name: string, x?: number, y?: number, floorId?: string) +获得某个点上怪物的某个属性值 + getSpecialColor: fn(enemy: string|enemy) -> [string] 获得某个怪物所有特殊属性的颜色 @@ -998,6 +1001,9 @@ load: fn(fromUserAction?: bool) lose: fn(reason?: string) 游戏失败事件 +moveEnemyOnPoint: fn(fromX: number, fromY: number, toX: number, toY: number, floorId?: string) +将某个点已经设置的敌人属性移动到其他点 + moveImage: fn(code: number, to?: [number], opacityVal?: number, time?: number, callback?: fn()) 移动一张图片并/或改变其透明度 例如:core.moveImage(1, null, 0.5); // 1秒内把1号图片变为50%透明 @@ -1063,6 +1069,9 @@ registerSystemEvent: fn(type: string, func: fn(data?: ?, callback?: fn())) type: 事件名 func: 为事件的处理函数,可接受(data,callback)参数 +resetEnemyOnPoint: fn(x: number, y: number, floorId?: string) +重置某个点的怪物属性 + resetGame: fn(hero?: ?, hard?: ?, floorId?: string, maps?: ?, values?: ?) 初始化游戏 @@ -1081,6 +1090,10 @@ value: 属性的新值,可选 operator: 运算操作符,可选 prefix: 独立开关前缀,一般不需要,下同 +setEnemyOnPoint: fn(x: number, y: number, floorId?: string, name: string, value: ?, operator?: string, prefix?: string) +设置某个点的敌人属性。如果该点不是怪物,则忽略此函数。 +例如:core.setEnemyOnPoint(3, 5, null, 'atk', 100, '+='); // 仅将(3,5)点怪物的攻击力加100。 + setEvents: fn(list?: [?], x?: number, y?: number, callback?: fn()) 直接设置事件列表 diff --git a/_server/CodeMirror/defs.js b/_server/CodeMirror/defs.js index ac9f2c53..e58540a1 100644 --- a/_server/CodeMirror/defs.js +++ b/_server/CodeMirror/defs.js @@ -3605,6 +3605,10 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!doc": "获得所有怪物原始数据的一个副本。
请使用core.material.enemys获得当前各项怪物属性。", "!type": "fn()" }, + "getEnemyValue": { + "!doc": "获得某个点上怪物的某个属性值", + "!type": "fn(enemy?: string|enemy, name: string, x?: number, y?: number, floorId?: string)" + }, "getSpecials": { "!doc": "获得所有特殊属性的定义", "!type": "fn() -> [[?]]" @@ -3908,6 +3912,18 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!doc": "设置一项敌人属性并计入存档
例如:core.setEnemy('greenSlime', 'def', 0); // 把绿头怪的防御设为0
id: 敌人id
name: 属性的英文缩写
value: 属性的新值,可选
operator: 运算操作符如+=,可选
prefix: 独立开关前缀,一般不需要,下同", "!type": "fn(id: string, name: string, value: ?, operator?: string, prefix?: string)" }, + "setEnemyOnPoint": { + "!doc": "设置某个点的敌人属性。如果该点不是怪物,则忽略此函数。
例如:core.setEnemyOnPoint(3, 5, null, 'atk', 100, '+='); // 仅将(3,5)点怪物的攻击力加100。", + "!type": "fn(x: number, y: number, floorId?: string, name: string, value: ?, operator?: string, prefix?: string)" + }, + "resetEnemyOnPoint": { + "!doc": "重置某个点的怪物属性", + "!type": "fn(x: number, y: number, floorId?: string)" + }, + "moveEnemyOnPoint": { + "!doc": "将某个点已经设置的敌人属性移动到其他点", + "!type": "fn(fromX: number, fromY: number, toX: number, toY: number, floorId?: string)" + }, "autoEventExecuting": { "!doc": "当前是否在执行某个自动事件", "!type": "fn(symbol?: string, value?: ?) -> bool" diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 6f28f112..924b1476 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -640,6 +640,9 @@ action | tip_s | setValue_s | setEnemy_s + | setEnemyOnPoint_s + | resetEnemyOnPoint_s + | moveEnemyOnPoint_s | setFloor_s | setGlobalAttribute_s | setGlobalValue_s @@ -1022,7 +1025,7 @@ setEnemy_s /* setEnemy_s tooltip : setEnemy:设置某个怪物的属性 helpUrl : /_docs/#/instruction -default : ["greenSlime", "atk", "0"] +default : ["greenSlime", "atk", "="] allEnemys : ['IdString_0'] colour : this.dataColor if (AssignOperator_List_0 && AssignOperator_List_0 != '=') { @@ -1033,6 +1036,62 @@ return code; */; +setEnemyOnPoint_s + : '设置某点怪物属性' ':' 'x' PosString? ',' 'y' PosString? '楼层' IdString? '的' EnemyId_List AssignOperator_List expression Newline + + +/* setEnemyOnPoint_s +tooltip : setEnemyOnPoint:设置某个点上怪物的属性 +helpUrl : /_docs/#/instruction +default : ["", "", "", "atk", "="] +selectPoint : ["PosString_0", "PosString_1", "IdString_0"] +allFloorIds : ['IdString_0'] +colour : this.dataColor +if (AssignOperator_List_0 && AssignOperator_List_0 != '=') { + AssignOperator_List_0 = ', "operator": "' + AssignOperator_List_0 + '"'; +} else AssignOperator_List_0 = ''; +IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); +var floorstr = PosString_0 && PosString_1 ? ', "loc": ['+PosString_0+','+PosString_1+']' : ''; +var code = '{"type": "setEnemyOnPoint"'+floorstr+IdString_0+', "name": "'+EnemyId_List_0+'"'+AssignOperator_List_0+', "value": "'+expression_0+'"},\n'; +return code; +*/; + +resetEnemyOnPoint_s + : '重置某点怪物属性' ':' 'x' PosString? ',' 'y' PosString? '楼层' IdString? Newline + + +/* resetEnemyOnPoint_s +tooltip : resetEnemyOnPoint:重置某个点上怪物的属性 +helpUrl : /_docs/#/instruction +default : ["", "", ""] +selectPoint : ["PosString_0", "PosString_1", "IdString_0"] +allFloorIds : ['IdString_0'] +colour : this.dataColor +IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); +var floorstr = PosString_0 && PosString_1 ? ', "loc": ['+PosString_0+','+PosString_1+']' : ''; +var code = '{"type": "resetEnemyOnPoint"'+floorstr+IdString_0+'},\n'; +return code; +*/; + +moveEnemyOnPoint_s + : '移动某点怪物属性' ':' '起点' 'x' PosString? ',' 'y' PosString? '终点' 'x' PosString? 'y' PosString? '楼层' IdString? Newline + + +/* moveEnemyOnPoint_s +tooltip : moveEnemyOnPoint:移动某个点上怪物的属性到其他点 +helpUrl : /_docs/#/instruction +default : ["", "", "", "", ""] +allFloorIds : ['IdString_0'] +selectPoint : ["PosString_2", "PosString_3"] +menu : [['选择起点位置','editor_blockly.selectPoint(block,["PosString_0", "PosString_1"])']] +colour : this.dataColor +IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); +var floorstr = PosString_0 && PosString_1 ? ', "from": ['+PosString_0+','+PosString_1+']' : ''; +if (PosString_2 && PosString_3) floorstr += ', "to": ['+PosString_2+','+PosString_3+']' +var code = '{"type": "moveEnemyOnPoint"'+floorstr+IdString_0+'},\n'; +return code; +*/; + setFloor_s : '设置楼层属性' ':' Floor_Meta_List '楼层名' IdString? '为' JsonEvalString Newline diff --git a/_server/MotaActionParser.js b/_server/MotaActionParser.js index 4338e92a..cc917a69 100644 --- a/_server/MotaActionParser.js +++ b/_server/MotaActionParser.js @@ -628,6 +628,22 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['setEnemy_s'].xmlText([ MotaActionFunctions.replaceToName_token(data.id), data.name, data["operator"]||'=', this.expandEvalBlock([data.value]), this.next]); break; + case "setEnemyOnPoint": + data.loc=data.loc||['',''] + this.next = MotaActionBlocks['setEnemyOnPoint_s'].xmlText([ + data.loc[0], data.loc[1], data.floorId||'', data.name, data["operator"]||'=', this.expandEvalBlock([data.value]), this.next]); + break; + case "resetEnemyOnPoint": + data.loc=data.loc||['',''] + this.next = MotaActionBlocks['resetEnemyOnPoint_s'].xmlText([ + data.loc[0], data.loc[1], data.floorId||'',this.next]); + break; + case "moveEnemyOnPoint": + data.from=data.from||['',''] + data.to=data.to||['',''] + this.next = MotaActionBlocks['moveEnemyOnPoint_s'].xmlText([ + data.from[0], data.from[1], data.to[0], data.to[1], data.floorId||'',this.next]); + break; case "setFloor": this.next = MotaActionBlocks['setFloor_s'].xmlText([ data.name, data.floorId||null, JSON.stringify(data.value), this.next]); diff --git a/_server/editor_blocklyconfig.js b/_server/editor_blocklyconfig.js index a3a5f81f..780d5d75 100644 --- a/_server/editor_blocklyconfig.js +++ b/_server/editor_blocklyconfig.js @@ -117,6 +117,9 @@ editor_blocklyconfig=(function(){ MotaActionBlocks['idIdList_e'].xmlText(['status','生命']), '=', '', false ]), MotaActionBlocks['setEnemy_s'].xmlText(), + MotaActionBlocks['setEnemyOnPoint_s'].xmlText(), + MotaActionBlocks['resetEnemyOnPoint_s'].xmlText(), + MotaActionBlocks['moveEnemyOnPoint_s'].xmlText(), MotaActionBlocks['setFloor_s'].xmlText(), MotaActionBlocks['setGlobalAttribute_s'].xmlText(), MotaActionBlocks['setGlobalValue_s'].xmlText(), diff --git a/libs/enemys.js b/libs/enemys.js index 2dacd65f..19c1d0e1 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -144,6 +144,22 @@ enemys.prototype._calSpecialContent = function (enemy, content) { return ""; } +////// 获得某个点上某个怪物的某项属性 ////// +enemys.prototype.getEnemyValue = function (enemy, name, x, y, floorId) { + floorId = floorId || core.status.floorId; + if ((((flags.enemyOnPoint||{})[floorId]||{})[x+","+y]||{})[name] != null) { + return flags.enemyOnPoint[floorId][x+","+y][name]; + } + if (enemy == null) { + var block = core.getBlock(x, y, floorId); + if (block == null) return null; + enemy = core.material.enemys[block.event.id]; + } + if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; + if (enemy == null) return null; + return enemy[name]; +} + ////// 能否获胜 ////// enemys.prototype.canBattle = function (enemy, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; diff --git a/libs/events.js b/libs/events.js index 70ba3dca..83f83fde 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1198,7 +1198,7 @@ events.prototype.__precompile_getArray = function () { "show", "hide", "setBlock", "showFloorImg", "hideFloorImg", "showBgFgMap", "hideBgFgMap", "setBgFgBlock", "animate", "setViewport", "move", "jumoHero", "changeFloor", "changePos", "showTextImage", "showGif", "openDoor", - "closeDoor", "battle", "trigger", "insert" + "closeDoor", "battle", "trigger", "insert", "setEnemyOnPoint", "resetEnemyOnPoint" ]; var values = [ "setValue", "setEnemy", "setFloor", "setGlobalValue", @@ -1753,6 +1753,31 @@ events.prototype._action_setEnemy = function (data, x, y, prefix) { core.doAction(); } +events.prototype._action_setEnemyOnPoint = function (data, x, y, prefix) { + var loc = this.__action_getLoc(data.loc, x, y, prefix); + this.setEnemyOnPoint(loc[0], loc[1], data.floorId, data.name, data.value, data.operator, prefix); + core.doAction(); +} + +events.prototype._action_resetEnemyOnPoint = function (data, x, y, prefix) { + var loc = this.__action_getLoc(data.loc, x, y, prefix); + this.resetEnemyOnPoint(loc[0], loc[1], data.floorId); + core.doAction(); +} + +events.prototype._precompile_moveEnemyOnPoint = function (data) { + data.from = this.__precompile_array(data.from); + data.to = this.__precompile_array(data.to); + return data; +} + +events.prototype._action_moveEnemyOnPoint = function (data, x, y, prefix) { + var from = this.__action_getLoc(data.from, x, y, prefix); + var to = this.__action_getLoc(data.to, x, y, prefix); + this.moveEnemyOnPoint(from[0], from[1], to[0], to[1], data.floorId); + core.doAction(); +} + events.prototype._action_setFloor = function (data, x, y, prefix) { this.setFloorInfo(data.name, data.value, data.floorId, prefix); core.doAction(); @@ -2729,6 +2754,38 @@ events.prototype.setEnemy = function (id, name, value, operator, prefix) { core.updateStatusBar(); } +////// 设置某个点上的怪物属性 ////// +events.prototype.setEnemyOnPoint = function (x, y, floorId, name, value, operator, prefix) { + floorId = floorId || core.status.floorId; + var block = core.getBlock(x, y, floorId); + if (block == null) return; + if (block.event.cls.indexOf('enemy') != 0) return; + var enemy = core.material.enemys[block.event.id]; + if (enemy == null) return; + value = this._updateValueByOperator(core.calValue(value, prefix), enemy[name], operator); + flags.enemyOnPoint = flags.enemyOnPoint || {}; + flags.enemyOnPoint[floorId] = flags.enemyOnPoint[floorId] || {}; + flags.enemyOnPoint[floorId][x+","+y] = flags.enemyOnPoint[floorId][x+","+y] || {}; + flags.enemyOnPoint[floorId][x+","+y][name] = value; + core.updateStatusBar(); +} + +////// 重置某个点上的怪物属性 ////// +events.prototype.resetEnemyOnPoint = function (x, y, floorId) { + delete ((flags.enemyOnPoint||{})[floorId||core.status.floorId]||{})[x+","+y]; + core.updateStatusBar(); +} + +////// 将某个点上已经设置的怪物属性移动到其他点 ////// +events.prototype.moveEnemyOnPoint = function (fromX, fromY, toX, toY, floorId) { + floorId = floorId || core.status.floorId; + if (((flags.enemyOnPoint||{})[floorId]||{})[fromX+","+fromY]) { + flags.enemyOnPoint[floorId][toX+","+toY] = flags.enemyOnPoint[floorId][fromX+","+fromY]; + delete flags.enemyOnPoint[floorId][fromX+","+fromY]; + core.updateStatusBar(); + } +} + ////// 设置楼层属性 ////// events.prototype.setFloorInfo = function (name, value, floorId, prefix) { floorId = floorId || core.status.floorId; diff --git a/libs/maps.js b/libs/maps.js index fc8dc62b..31655939 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -2251,7 +2251,7 @@ maps.prototype.moveBlock = function (x, y, steps, time, keep, callback) { this._moveDetachedBlock(blockInfo, 32 * x, 32 * y, 1, canvases); var moveInfo = { - x: x, y: y, px: 32 * x, py: 32 * y, opacity: 1, keep: keep, lastDirection: null, offset: 1, + sx: x, sy: y, x: x, y: y, px: 32 * x, py: 32 * y, opacity: 1, keep: keep, lastDirection: null, offset: 1, moveSteps: moveSteps, step: 0, per_time: time / 16 / core.status.replay.speed } this._moveBlock_doMove(blockInfo, canvases, moveInfo, callback); @@ -2345,7 +2345,7 @@ maps.prototype.__generateJumpInfo = function (sx, sy, ex, ey, time) { var jump_peak = 6 + distance, jump_count = jump_peak * 2; time /= Math.max(core.status.replay.speed, 1) return { - x: sx, y: sy, ex: ex, ey: ey, px: 32 * sx, py: 32 * sy, opacity: 1, + sx: sx, sy: sy, x: sx, y: sy, ex: ex, ey: ey, px: 32 * sx, py: 32 * sy, opacity: 1, jump_peak: jump_peak, jump_count: jump_count, step: 0, per_time: time / jump_count }; @@ -2387,6 +2387,7 @@ maps.prototype._moveJumpBlock_finished = function (blockInfo, canvases, info, an if (info.keep) { core.setBlock(blockInfo.number, info.x, info.y); core.showBlock(info.x, info.y); + core.moveEnemyOnPoint(info.sx, info.sy, info.x, info.y); } if (callback) callback(); } diff --git a/project/functions.js b/project/functions.js index cbf4675f..8de169ce 100644 --- a/project/functions.js +++ b/project/functions.js @@ -395,6 +395,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 如果事件不为空,将其插入 if (todo.length > 0) core.insertAction(todo, x, y); + // 删除该点设置的怪物信息 + delete ((flags.enemyOnPoint||{})[core.status.floorId]||{})[x+","+y]; + // 因为removeBlock和hideBlock都会刷新状态栏,因此将删除部分移动到这里并保证刷新只执行一次,以提升效率 if (core.getBlock(x, y) != null) { // 检查是否是重生怪物;如果是则仅隐藏不删除 @@ -513,13 +516,13 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = hero_def = core.getRealStatusOrDefault(hero, 'def'), hero_mdef = core.getRealStatusOrDefault(hero, 'mdef'); - var mon_hp = enemy.hp, - mon_atk = enemy.atk, - mon_def = enemy.def, - mon_special = enemy.special; - var mon_money = enemy.money, - mon_exp = enemy.exp, - mon_point = enemy.point; + var mon_hp = core.getEnemyValue(enemy, 'hp', x, y, floorId), + mon_atk = core.getEnemyValue(enemy, 'atk', x, y, floorId), + mon_def = core.getEnemyValue(enemy, 'def', x, y, floorId), + mon_special = core.getEnemyValue(enemy, 'special', x, y, floorId); + var mon_money = core.getEnemyValue(enemy, 'money', x, y, floorId), + mon_exp = core.getEnemyValue(enemy, 'exp', x, y, floorId), + mon_point = core.getEnemyValue(enemy, 'point', x, y, floorId); // 模仿 if (core.hasSpecial(mon_special, 10)) { mon_atk = hero_atk; diff --git a/runtime.d.ts b/runtime.d.ts index 2d83b40f..e9b231a6 100644 --- a/runtime.d.ts +++ b/runtime.d.ts @@ -912,6 +912,15 @@ declare class events { */ setEnemy(id: string, name: K, value?: Enemy[K], operator?: string, prefix?: string): void + /** 设置某个点的敌人属性 */ + setEnemyOnPoint(x: number, y: number, floorId: string, name: K, value?: Enemy[K], operator?: string, prefix?: string): void + + /** 重置某个点的敌人属性 */ + resetEnemyOnPoint(x: number, y: number, floorId?: string): void + + /** 将某个点已经设置的敌人属性移动到其他点 */ + moveEnemyOnPoint(fromX: number, fromY: number, toX: number, toY: number, floorId?: string): void + /** * 设置一项楼层属性并刷新状态栏 * @example core.setFloorInfo('ratio', 2, 'MT0'); // 把主塔0层的血瓶和宝石变为双倍效果 @@ -1306,6 +1315,9 @@ declare class enemys { */ getSpecialHint(enemy: string | Enemy, special: number): string + /** 获得某个敌人的某项属性值 */ + getEnemyValue(enemy: string | Enemy, name: string, x?: number, y?: number, floorId?: string): any + /** * 判定主角当前能否打败某只敌人 * @example core.canBattle('greenSlime',0,0,'MT0') // 能否打败主塔0层左上角的绿头怪(假设有)