查看: 1217|回复: 9

[有事请教] 心烦啊...ai写代码死路一条

[复制链接]
梦石
0
星屑
528
在线时间
56 小时
注册时间
2022-7-8
回帖
23
发表于 2026-4-17 21:28:43 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有账号?注册会员

×
想做个地域压制类战斗系统(就是玩家扮演的角色带兵,武器替换为兵种HP替换为人力,战斗画面就是一队人打另一队人之类的)结果遇到问题死活解决不了,干脆死了这条心吧......
[pre lang="js"]//=============================================================================
// RTB_ArmyBattle.js
//=============================================================================
// 版本: 2.5.1 (Save Before Call)
// 描述: 英雄带兵战斗系统 - 彻底修复首次攻击不显示
//=============================================================================

/*:
* @target MZ
* @plugindesc v2.5.1 英雄带兵战斗系统 (数据保存版)
* @author YourName
* @help
* ============================================================================
* 插件说明
* ============================================================================
* 此插件将RPG Maker MZ的默认战斗界面改造为带兵打仗风格。
*
* 主要特性:
* - 上方显示敌人头像、名称、HP条(隐藏默认敌人战斗图)
* - 攻击时,左侧出现我方部队,右侧出现敌方部队
* - 兵模图片从 /img/pictures/ 文件夹读取
* - 若未配置映射,自动使用默认图片:Actor1_1, Actor1_2, Actor1_3
*
* @param generalMapping
* @text 将领图片映射
* @desc 角色ID与将领图片的对应关系。格式: ["1:图片名","2:图片名"]
* @type string[]
* @default ["1:Actor1_1"]
*
* @param supportMapping
* @text 支援兵器映射
* @desc 防具ID与支援兵器图片的对应关系。格式: ["1:图片名","2:图片名"]
* @type string[]
* @default ["1:Actor1_2"]
*
* @param troopMapping
* @text 兵种映射
* @desc 武器ID:兵模图片:类型:每单位人力。
* @type string[]
* @default ["1:Actor1_3:infantry:1"]
*
* @param enemyGeneralMapping
* @text 敌将图片映射
* @desc 敌人ID与将领图片的对应关系。
* @type string[]
* @default ["1:Monster_1"]
*
* @param enemyTroopMapping
* @text 敌兵种映射
* @desc 敌人ID:兵模图片:类型:每单位人力。
* @type string[]
* @default ["1:Monster_2:infantry:1"]
*
* @param enemyAvatarMapping
* @text 敌人头像映射
* @desc 敌人ID与头像图片的对应关系,用于上方敌人列表显示。
* @type string[]
* @default ["1:Monster_3"]
*/

(() => {
    'use strict';

    console.log('[RTB] 插件初始化开始');

    //=============================================================================
    // 参数解析 (完全容错)
    //=============================================================================
    const parameters = PluginManager.parameters('RTB_ArmyBattle');
   
    function safeJsonParse(str, defaultValue = []) {
        if (!str) return defaultValue;
        try {
            return JSON.parse(str);
        } catch (e) {
            console.warn('[RTB] 参数解析失败,使用默认值。', str);
            return defaultValue;
        }
    }

    const GENERAL_MAP_RAW = safeJsonParse(parameters.generalMapping, ["1:Actor1_1"]);
    const SUPPORT_MAP_RAW = safeJsonParse(parameters.supportMapping, ["1:Actor1_2"]);
    const TROOP_MAP_RAW = safeJsonParse(parameters.troopMapping, ["1:Actor1_3:infantry:1"]);
    const ENEMY_GENERAL_MAP_RAW = safeJsonParse(parameters.enemyGeneralMapping, ["1:Monster_1"]);
    const ENEMY_TROOP_MAP_RAW = safeJsonParse(parameters.enemyTroopMapping, ["1:Monster_2:infantry:1"]);
    const ENEMY_AVATAR_MAP_RAW = safeJsonParse(parameters.enemyAvatarMapping, ["1:Monster_3"]);

    function parseSimpleMapping(rawArray) {
        const map = new Map();
        for (const entry of rawArray) {
            if (typeof entry !== 'string') continue;
            const parts = entry.split(':');
            if (parts.length >= 2) {
                const id = Number(parts[0]);
                const name = parts[1].trim();
                if (!isNaN(id) && name) map.set(id, name);
            }
        }
        return map;
    }

    function parseTroopMapping(rawArray) {
        const map = new Map();
        for (const entry of rawArray) {
            if (typeof entry !== 'string') continue;
            const parts = entry.split(':');
            if (parts.length >= 4) {
                const id = Number(parts[0]);
                const imageName = parts[1].trim();
                const type = parts[2].trim().toLowerCase();
                const unitHp = Number(parts[3]);
                if (!isNaN(id) && imageName) {
                    map.set(id, { imageName, type, unitHp });
                }
            }
        }
        return map;
    }

    const GENERAL_MAP = parseSimpleMapping(GENERAL_MAP_RAW);
    const SUPPORT_MAP = parseSimpleMapping(SUPPORT_MAP_RAW);
    const TROOP_MAP = parseTroopMapping(TROOP_MAP_RAW);
    const ENEMY_GENERAL_MAP = parseSimpleMapping(ENEMY_GENERAL_MAP_RAW);
    const ENEMY_TROOP_MAP = parseTroopMapping(ENEMY_TROOP_MAP_RAW);
    const ENEMY_AVATAR_MAP = parseSimpleMapping(ENEMY_AVATAR_MAP_RAW);

    console.log('[RTB] 映射加载完成');

    //=============================================================================
    // 工具函数
    //=============================================================================
    function calculateTroopCount(currentHp, troopType, unitHp) {
        if (currentHp <= 0) return 0;
        const base = (unitHp && unitHp > 0) ? unitHp : (troopType === 'armor' ? 10 : 1);
        return Math.max(1, Math.ceil(currentHp / base));
    }

    function getActorForceData(actor) {
        const actorId = actor.actorId();
        const weapon = actor.weapons()[0];
        const armor = actor.armors()[0];
        
        let generalImage = GENERAL_MAP.get(actorId) || 'Actor1_1';
        let supportImage = armor ? (SUPPORT_MAP.get(armor.id) || 'Actor1_2') : '';
        let troopImage = 'Actor1_3';
        let troopType = 'infantry';
        let unitHp = 1;
        
        if (weapon) {
            const troopInfo = TROOP_MAP.get(weapon.id);
            if (troopInfo) {
                troopImage = troopInfo.imageName;
                troopType = troopInfo.type;
                unitHp = troopInfo.unitHp;
            }
        }

        const soldierCount = calculateTroopCount(actor.hp, troopType, unitHp);
        return { generalImage, supportImage, troopImage, troopType, soldierCount };
    }

    function getEnemyForceData(enemy) {
        const enemyId = enemy.enemyId();
        const troopInfo = ENEMY_TROOP_MAP.get(enemyId);
        let troopImage = troopInfo ? troopInfo.imageName : 'Monster_2';
        let troopType = troopInfo ? troopInfo.type : 'infantry';
        let unitHp = troopInfo ? troopInfo.unitHp : 1;
        let generalImage = ENEMY_GENERAL_MAP.get(enemyId) || 'Monster_1';
        const soldierCount = calculateTroopCount(enemy.hp, troopType, unitHp);
        return { generalImage, troopImage, troopType, soldierCount };
    }

    //=============================================================================
    // 窗口:上方敌人状态列表
    //=============================================================================
    class Window_TroopStatus extends Window_Base {
        initialize() {
            const w = Graphics.boxWidth;
            const h = 180;
            super.initialize(new Rectangle(0, 0, w, h));
            this._enemies = [];
            this.opacity = 192;
            this.refresh();
        }

        setEnemies(enemies) {
            this._enemies = enemies || [];
            this.refresh();
        }

        refresh() {
            this.contents.clear();
            if (!this._enemies.length) return;
            const itemWidth = 200;
            const padding = 10;
            const startX = 20;
            const y = 0;
            this._enemies.forEach((enemy, index) => {
                const x = startX + index * (itemWidth + padding);
                this.drawEnemyItem(enemy, x, y, itemWidth);
            });
        }

        drawEnemyItem(enemy, x, y, width) {
            const enemyId = enemy.enemyId();
            const avatarName = ENEMY_AVATAR_MAP.get(enemyId) || 'Monster_3';
            try {
                const bitmap = ImageManager.loadPicture(avatarName);
                this.contents.blt(bitmap, 0, 0, 48, 48, x, y, 48, 48);
            } catch (e) {
                try {
                    this.drawIcon(1, x, y);
                } catch (e2) {}
            }
            this.drawText(enemy.name(), x + 54, y, width - 54, 'left');
            
            const hpY = y + 24;
            const hpWidth = width - 54;
            const rate = enemy.hpRate();
            const barHeight = 12;
            this.contents.fillRect(x + 54, hpY, hpWidth, barHeight, '#000000');
            const color1 = ColorManager.textColor(20);
            const fillW = Math.max(0, Math.floor((hpWidth - 2) * rate));
            this.contents.fillRect(x + 55, hpY + 1, fillW, barHeight - 2, color1);
            this.drawText(`${enemy.hp}/${enemy.mhp}`, x + 54, hpY + barHeight, hpWidth, 'right');
        }

        update() {
            super.update();
            if (this._enemies.length) this.refresh();
        }
    }

    //=============================================================================
    // 隐藏默认敌人精灵
    //=============================================================================
    const _Spriteset_Battle_createEnemies = Spriteset_Battle.prototype.createEnemies;
    Spriteset_Battle.prototype.createEnemies = function() {
        _Spriteset_Battle_createEnemies.call(this);
        if (this._enemySprites) {
            this._enemySprites.forEach(sprite => sprite.visible = false);
        }
    };

    const _Spriteset_Battle_update = Spriteset_Battle.prototype.update;
    Spriteset_Battle.prototype.update = function() {
        _Spriteset_Battle_update.call(this);
        if (this._enemySprites) {
            this._enemySprites.forEach(sprite => sprite.visible = false);
        }
    };

    //=============================================================================
    // 场景战斗扩展:创建容器和部队显示方法
    //=============================================================================
    const _Scene_Battle_createDisplayObjects = Scene_Battle.prototype.createDisplayObjects;
    Scene_Battle.prototype.createDisplayObjects = function() {
        _Scene_Battle_createDisplayObjects.call(this);
        this._troopStatusWindow = new Window_TroopStatus();
        this.addWindow(this._troopStatusWindow);
        this._troopStatusWindow.setEnemies($gameTroop.members());
        
        // 确保容器存在
        if (this._spriteset) {
            this._spriteset._leftArmyContainer = new PIXI.Container();
            this._spriteset._rightArmyContainer = new PIXI.Container();
            // 添加到 _baseSprite 或直接添加到 spriteset
            const target = this._spriteset._baseSprite || this._spriteset;
            target.addChild(this._spriteset._leftArmyContainer);
            target.addChild(this._spriteset._rightArmyContainer);
        }
    };

    const _Scene_Battle_update = Scene_Battle.prototype.update;
    Scene_Battle.prototype.update = function() {
        _Scene_Battle_update.call(this);
        if (this._troopStatusWindow) {
            this._troopStatusWindow.setEnemies($gameTroop.members());
        }
    };

    Scene_Battle.prototype.clearArmySprites = function() {
        const spriteset = this._spriteset;
        if (!spriteset) return;
        if (spriteset._leftArmyContainer) spriteset._leftArmyContainer.removeChildren();
        if (spriteset._rightArmyContainer) spriteset._rightArmyContainer.removeChildren();
        if (this._armyClearTimer) {
            clearTimeout(this._armyClearTimer);
            this._armyClearTimer = null;
        }
    };

    Scene_Battle.prototype.showLeftArmy = function(actorData) {
        const spriteset = this._spriteset;
        if (!spriteset || !spriteset._leftArmyContainer) return;
        spriteset._leftArmyContainer.removeChildren();
        const centerX = 200;
        const baseY = Graphics.boxHeight - 200;
        
        const addSprite = (img, x, y) => {
            if (!img) return;
            try {
                const bitmap = ImageManager.loadPicture(img);
                const sprite = new Sprite(bitmap);
                sprite.x = x;
                sprite.y = y;
                sprite.scale.set(0.8, 0.8);
                sprite.anchor.set(0.5, 1);
                spriteset._leftArmyContainer.addChild(sprite);
            } catch (e) {
                console.warn(`[RTB] 加载左侧图片失败: ${img}`);
            }
        };

        addSprite(actorData.generalImage, centerX - 40, baseY - 60);
        if (actorData.supportImage) {
            addSprite(actorData.supportImage, centerX + 60, baseY - 60);
        }
        if (actorData.soldierCount > 0) {
            const count = Math.min(actorData.soldierCount, 8);
            for (let i = 0; i < count; i++) {
                const offsetX = (i % 4) * 30 - 45;
                const offsetY = Math.floor(i / 4) * 25 + 20;
                addSprite(actorData.troopImage, centerX + offsetX, baseY + offsetY);
            }
        }
    };

    Scene_Battle.prototype.showRightArmy = function(enemyData) {
        const spriteset = this._spriteset;
        if (!spriteset || !spriteset._rightArmyContainer) return;
        spriteset._rightArmyContainer.removeChildren();
        const centerX = Graphics.boxWidth - 200;
        const baseY = Graphics.boxHeight - 200;
        
        const addSprite = (img, x, y) => {
            if (!img) return;
            try {
                const bitmap = ImageManager.loadPicture(img);
                const sprite = new Sprite(bitmap);
                sprite.x = x;
                sprite.y = y;
                sprite.scale.set(0.8, 0.8);
                sprite.anchor.set(0.5, 1);
                spriteset._rightArmyContainer.addChild(sprite);
            } catch (e) {
                console.warn(`[RTB] 加载右侧图片失败: ${img}`);
            }
        };

        addSprite(enemyData.generalImage, centerX - 40, baseY - 60);
        if (enemyData.soldierCount > 0) {
            const count = Math.min(enemyData.soldierCount, 8);
            for (let i = 0; i < count; i++) {
                const offsetX = (i % 4) * 30 - 45;
                const offsetY = Math.floor(i / 4) * 25 + 20;
                addSprite(enemyData.troopImage, centerX + offsetX, baseY + offsetY);
            }
        }
    };

    //=============================================================================
    // 拦截行动开始 (关键修正:先保存数据,再调原版)
    //=============================================================================
    const _BattleManager_startAction = BattleManager.startAction;
    BattleManager.startAction = function() {
        const action = this._action;
        const subject = this._subject;
        
        // 【关键】立即保存当前行动者和目标,避免被原版方法清空
        const isActorAction = subject && subject.isActor() && action;
        let actorData = null;
        let enemyData = null;
        
        if (isActorAction) {
            actorData = getActorForceData(subject);
            const targets = action.makeTargets();
            let target = targets.find(t => t.isEnemy());
            if (!target) {
                for (const t of targets) {
                    if (t.isEnemy()) { target = t; break; }
                }
            }
            if (target) enemyData = getEnemyForceData(target);
        }
        
        // 执行原版逻辑
        _BattleManager_startAction.call(this);
        
        // 显示部队
        if (isActorAction) {
            const scene = SceneManager._scene;
            if (!scene) return;
            
            console.log('[RTB] 角色行动,显示部队');
            
            if (scene._armyClearTimer) {
                clearTimeout(scene._armyClearTimer);
                scene._armyClearTimer = null;
            }
            
            scene.clearArmySprites();
            scene.showLeftArmy(actorData);
            if (enemyData) scene.showRightArmy(enemyData);
            
            // 设置清除定时器
            scene._armyClearTimer = setTimeout(() => scene.clearArmySprites(), 600);
        }
    };

    const _Scene_Battle_terminate = Scene_Battle.prototype.terminate;
    Scene_Battle.prototype.terminate = function() {
        if (this._armyClearTimer) {
            clearTimeout(this._armyClearTimer);
            this._armyClearTimer = null;
        }
        this.clearArmySprites();
        _Scene_Battle_terminate.call(this);
    };

    console.log('[RTB] 插件加载完成');
})();[/pre]

失败品截图

失败品截图

没用的焚诀

没用的焚诀

*这个人并不懒,但是他还是没有写

素材区好人

梦石
5
星屑
12559
在线时间
4345 小时
注册时间
2011-7-21
回帖
2264

超评测参与极短28参与极短27参与极短26参与极短25参与极短24参与极短23参与极短22参与极短21参与

发表于 2026-4-17 21:41:48 | 显示全部楼层
本帖最后由 无忧谷主幻 于 2026-4-17 22:03 编辑

ai只能解决一些简单的,复杂的就别想了
而且大多时候还需要不断修改

点评

俗称和ai battle  发表于 2026-4-20 13:49
回复

使用道具 举报

梦石
0
星屑
528
在线时间
56 小时
注册时间
2022-7-8
回帖
23
 楼主| 发表于 2026-4-17 21:57:03 | 显示全部楼层
自学插件都找不到去哪自学,要么狗屁不通要么太监......
*这个人并不懒,但是他还是没有写
回复

使用道具 举报

梦石
0
星屑
25352
在线时间
1136 小时
注册时间
2019-3-5
回帖
1303
发表于 2026-4-17 22:15:07 | 显示全部楼层
一枚菜鸡大队长 发表于 2026-4-17 21:57
自学插件都找不到去哪自学,要么狗屁不通要么太监......

你都会用AI了,问一句AI推荐编程入门网站有那么难么

另外d老师写代码水平一坨,能用推荐GPT,GPT应该被人喂过数据库,平常问他一些脚本幻觉不算厉害
回复

使用道具 举报

梦石
0
星屑
100
在线时间
1022 小时
注册时间
2021-3-24
回帖
544

MZ评测员

发表于 2026-4-18 00:00:50 | 显示全部楼层
请为 RPG Maker MZ 编写一个名为 EcoSystem_Core.js 的插件框架。
全局存储: 在 $gameSystem 中初始化一个名为 _ecoManager 的对象,用于存储每个地图的经济数据(包含:物品库存、当前物价倍率、需求列表)。
备注解析: 扩展 Game_Event.prototype.setupPage 方法。当事件启动时,解析其备注栏(Note)中的标签:<EcoConfig: produce[id:count], consume[id:count], initial[id:count]>。
数据绑定: 将解析出的生产(produce)、消耗(consume)和初始库存(initial)存入对应地图的数据结构中,并确保这些数据能随存档保存。
API接口: 提供一个方法 EcoManager.getMapData(mapId) 方便后续调用。
基于之前的框架,现在实现核心的经济模拟逻辑:
结算周期: 定义一个‘周’的概念(例如每 10000 帧或通过插件指令触发)。
生产与消费: 每周结算时,遍历所有地图的 NPC 事件。根据备注的 produce 增加地图总库存,根据 consume 减少总库存。
如果某种维生品(食物等)库存归零,记录该地图为‘短缺状态’。
动态定价公式: 实现一个定价算法。价格倍率 $P = (总需求 + 10) / (总库存 + 10)$。将该倍率更新到对应地图的 priceScale 中。
属性注入: 确保每个事件的库存是独立的,但会汇总到所属地图的宏观市场中。
现在为插件添加商会(Chamber of Commerce)系统:
地图距离矩阵: 允许在插件参数中定义一个简单的地图连接矩阵(例如:Map1 到 Map2 距离为 5,Map2 到 Map3 距离为 3)。
自动补货: 在每周结算后,检查‘短缺状态’的地图。商会会从最近的、库存充裕的地图调配物资。
物流成本: 跨地图购买的物资价格 = 来源地物价 + (距离 * 基础运费)。这个成本将计入目标地图的下一周物价计算中。
逻辑解耦: 商会的行为不需要在地图上显示,仅作为数据层面的库存转移和价格修正。


-----------------------------
像这样,你先和AI捞5块钱的
全家活光光~
回复

使用道具 举报

梦石
0
星屑
6334
在线时间
287 小时
注册时间
2018-1-22
回帖
207
发表于 2026-4-18 02:01:55 | 显示全部楼层
自学插件的前提是要懂js,真想学先从js入门开始,教程网上随便一搜就有
如果你没那个时间精力和想法,只想单纯玩玩AI的话 就得先从简单的逻辑开始训练,比如先从一个点移动到另一个点,然后播放一个攻击动画,再调用伤害逻辑、事件等等,一步步慢慢来,没有你这样上来就是一堆抽象描述的,说实话光凭这些信息真程序都不一定搞得出来
自分自身の神様になること
回复

使用道具 举报

梦石
0
星屑
3264
在线时间
776 小时
注册时间
2023-5-18
回帖
154
发表于 2026-4-18 07:46:07 | 显示全部楼层
RM官方就有教怎么写插件的官方教程,而且还是从js开始教
B站:传送门
-----------------------------------------------------------------------
“与其为做不到的事耿耿于怀,不如为自己做到的事而喜悦
吧!”

-----------------------------------------------------------------------
回复

使用道具 举报

梦石
0
星屑
7989
在线时间
1319 小时
注册时间
2006-7-18
回帖
459
发表于 2026-4-18 10:39:53 | 显示全部楼层
AI只能写一写简单的!改改UI,改改设定,想要大改系统太容易出问题了!
回复

使用道具 举报

梦石
0
星屑
3109
在线时间
661 小时
注册时间
2012-6-17
回帖
516

MZ评测员

发表于 2026-4-18 17:09:32 | 显示全部楼层
我也是劝你死了这条心

问渠那得清如许vs插件群:592798519  百鬼异闻录:887907636
为有源头活水来点击这里试玩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部