far语言写的回合制战斗逻辑




static map skillsConf = ({});


///*实际伤害 = [(攻击方.str + 攻击方.combatExp / 100) * (1 + 攻击方.int / 100)] - (防御方.con / 2)
//
//若 攻击方.dex / 防御方.dex > 随机数(0, 1),则攻击方躲避防御方反击
//若 防御方.dex / 攻击方.dex > 随机数(0, 1),则防御方躲避攻击,实际伤害 = 0*/

static number fight(object me, object victim){

    map kEntire = me.entityData();
    map vEntire = victim.entityData();
    //伤害
    number kdmg = ( kEntire["str"] + kEntire["combatExp"] / 100 ) * (1 + kEntire["int"] / 100) ;
    println(me.query("name")+" 开始伤害是"+kdmg);

    number vDef =  vEntire["con"] / 2;
    kdmg = kdmg - vDef;

    if (randomRange(0,5) < vEntire["dex"] / kEntire["dex"]){
        println("没打中");
    }else{
        vEntire["qi"] -= kdmg;
    }


    println(fmt("%s 气是 %s",victim.query("name"),vEntire["qi"]));

    if( vEntire["qi"] < 1  ){
        string msg = fmt("%s 口吐鲜血,一口气上不来死了。",victim.query("name"));
        tellObject(me,msg);
        println(msg);

        me.removeKiller(victim);
        victim.die();
//
        me.set("pot",me.query("pot")+20);
        tellObject(me,fmt("战斗胜利 修为 + %s",20));


        return 1;
    }

    println(fmt("%s(%s) -> %s(%s)",me.query("name"),kEntire["qi"],victim.query("name"),vEntire["qi"]));


}


//获取物理站位的名称
static string posDesc(number posId){
    string desc;
    if( posId==1 ){
        desc="左(后上)";
    }else if(posId==2){
        desc="左(后中)";
    }else if(posId==3){
        desc="左(后下)";
    }else if(posId==4){
        desc="左(前上)";
     }else if(posId==5){
         desc="左(前中)";
     }else if(posId==6){
         desc="左(前下)";
     }else if(posId==7){
          desc="右(前上)";
      }else if(posId==8){
          desc="右(前中)";
      }else if(posId==9){
          desc="右(前下)";
       }else if(posId==10){
           desc="右(后上)";
       }else if(posId==11){
           desc="右(后中)";
       }else if(posId==12){
           desc="右(后下)";
       }else{
            desc="位置数据错误!";
       }
       return desc;
}

static number getPosOf(number vPosId,map target){
    foreach(e in target){
        println(e);
    }
}
//计算伤害
static number calcDamage(map killer,map buf,number baseDamage){

 if(  buf["resultType"] > 1){//调整比例
    if( buf["refChangeType"]==1 && buf["refTarget"]==1){//增加模式
        baseDamage += baseDamage * buf["refChangeVal"];
    }
  }

  if(  sizeof(killer["effs"]) > 0 ){
    foreach( e in killer["effs"]){
        if( e["type"] == "减伤" && e["duration"] > 0){
            println(fmt("减伤 %s",baseDamage * e["refChangeVal"]));
            baseDamage-= baseDamage * e["refChangeVal"];
        }
    }
  }

  return baseDamage;
}

static number rdKill(map killer,map kSkillData,map kBuf, map victim,number currRound,string* combatMessage){


    //伤害
    number kdmg = ( killer["str"] + killer["combatExp"] / 100 ) * (1 + killer["int"] / 100) ;
//    println(killer["name"]+" 开始伤害是"+kdmg);

    number vDef =  victim["con"] / 2;
    kdmg = kdmg - vDef;
    number rand = randomRange(0,5);
    number dexRate = victim["dex"] / killer["dex"];


    var attackSk = killer["skills"]["attack"];

    if( !this::skillsConf ){
        println("skillConf没有数据啊!");
        return 1;
    }
    map skillData = kSkillData;
        //大当家(200/200, 能量:50/50)<左(前下)> 使出 十八摸(抓手)(消耗20能量) 攻击 李阿婆(200/200, 能量:50/50)<右(前上)>
      //→ 攻击命中!造成20.52点伤害(25攻-4.48防),附加迟缓(Buf 0,闪避-20%,持续2回合)
     // → 大当家能量剩余:30/50


    map buf = kBuf;//skillData["bufs"][random(sizeof(skillData["bufs"]))];
    map carryEffect = ({});
    //恢复类效果的值
    number recoverVal;

    object kOb = killer["teamLeader"];
    object vOb = victim["teamLeader"];
    string skName = skillData["name"];
    string skBufName = buf["name"];
    string kPosDesc = this::posDesc(killer["pPos"]);
    string vPosDesc = this::posDesc(victim["pPos"]);
    string* kmsg;
//    string batMsg1 = fmt("%s(%s)<%s> 使出 %s(%s) 攻击 %s(%s)<%s> ",killer["name"],killer["qi"],kPosDesc,  skillData["name"],buf["name"],victim["name"],victim["qi"],vPosDesc);

    //[回合N] 大当家(气血:200/200 | 能量:50/50)<左(前下)> 释放技能「十八摸·抓手」(消耗能量20)
    string kStr =  fmt("[回合%s] %s(气:%s/%s | 能:%s/%s)<%s>",currRound,killer["name"],killer["qi"],killer["maxQi"],killer["neili"],killer["maxNeili"],kPosDesc);
    string vStr = fmt(" -> 目标: %s(气:%s/%s | 能:%s/%s)<%s>\n",victim["name"],victim["qi"],victim["maxQi"],victim["neili"],victim["maxNeili"],vPosDesc);
    string btMsg="";

    string kTitle = fmt("%s(气 %s/%s 能 %s/%s)<%s>",killer["name"],killer["qi"],killer["maxQi"],killer["neili"],killer["maxNeili"],kPosDesc);
    string vTitle = fmt("%s(气 %s/%s 能 %s/%s)<%s>",victim["name"],victim["qi"],victim["maxQi"],victim["neili"],victim["maxNeili"],vPosDesc);
    string actType;
    string skillMsg;
    string batMsg;
    string effMsg="";

// [回合1] 大当家(气血:200/200 | 能量:50/50)<左(前下)> 释放技能「十八摸·抓手」(消耗能量20)
//   → 目标:李阿婆(气血:200/200 | 能量:50/50)<右(前上)>
//   → 计算:攻击强度25 - 目标防御4.48 = 基础伤害20.52
//   → 结果:命中!造成**20.52点伤害**(气血剩余:**179.48/200**)
//   → 附加效果:迟缓(Buf ID:0 | 闪避-20% | 持续2回合)
//   → 执行者状态:能量剩余**30/50**
//
//// [回合2] 李阿婆(气血:179.48/200 | 能量:50/50)<右(前上)> 普通攻击 大当家(气血:200/200 | 能量:30/50)<左(前下)>
//   → 计算:攻击强度15 - 目标防御8 = 基础伤害7
//   → 结果:未命中!(受迟缓影响,闪避+20%)
//   → 执行者状态:能量无消耗 **50/50**
//
//// [回合3] 大当家(气血:200/200 | 能量:30/50)<左(前下)> 释放技能「十八摸·锁喉」(消耗能量30)
//   → 目标:李阿婆(气血:179.48/200 | 能量:50/50)<右(前上)>
//   → 计算:攻击强度30(暴击!×1.2)- 目标防御4.48 = 基础伤害31.52
//   → 结果:暴击命中!造成**31.52点伤害**(气血剩余:179.48 - 31.52 = **147.96/200**)
//   → 附加效果:流血(每回合损失5%气血,持续3回合)
//   → 执行者状态:能量剩余30 - 30 = **0/50**(下一回合无法释放技能)

    number hitTrue = 0;
    //执行前的能量
    number befNeili = killer["neili"];
    skillMsg = fmt("使出 %s(%s)",skName,skBufName);
    if( buf["type"]=="物理攻击" ){
        kdmg = calcDamage(killer,buf,kdmg);

        actType = "攻击";
        if (rand < dexRate){
            batMsg = fmt("但没打中%s",victim["name"]);

            btMsg+=fmt(" -> 结果:未命中 原因 %s < %s\n",rand,dexRate);

        }else{

             hitTrue = 1;

             btMsg+=fmt(" -> 结果:命中 造成 %s 点伤害,目标气血剩余 %s - %s =",kdmg,victim["qi"],kdmg);

             victim["qi"] -= kdmg;

             btMsg+=fmt(" %s\n",victim["qi"]);

            //会不会给对方贴上buf?
            if( has( buf,"afterEffect") && has(buf["afterEffect"],"effs") && sizeof(buf["afterEffect"]["effs"]) > 0 ){
                foreach( e in buf["afterEffect"]["effs"] ){
                    if( !canSetBuf(victim,e) ) continue;

                    e["duration"] = e["cycle"];
                    effMsg+=fmt(" %s 持续%s回合、",e["name"],e["cycle"]);

                    if( !victim["effs"] ){
                        victim["effs"] = ([]);
                        victim["effs"]+=e;
                    }else{
                         victim["effs"]+=e;
                    }
                }
            }
            batMsg = fmt("造成 %s 点伤害。",kdmg);
            if( effMsg ){
                btMsg+=fmt(" -> 附加效果:%s\n",effMsg);
                batMsg+= "还附加了Buf "+effMsg;
            }
        }
    }
    else if( buf["type"] == "治疗"){

//        var aef = buf["afterEffect"]["bufs"][0];
        carryEffect["triggerOdds"]      = buf["triggerOdds"];
        carryEffect["refChangeVal"]     = buf["refChangeVal"];
        carryEffect["resultType"]       = buf["resultType"];
        carryEffect["refTarget"]        = buf["refTarget"];
        carryEffect["refChangeType"]    = buf["refChangeType"];
        carryEffect["costNeili"]        = buf["costNeili"];

        if( buf["resultType"] > 1 && buf["refChangeType"]==1 ){//增加模式
            if(  carryEffect["refTarget"]==4  ){
                recoverVal = victim["maxQi"] * buf["refChangeVal"];
            }
        }
        number costNeili = killer["maxNeili"] * buf["costNeili"] ;

        actType = "治疗";
//        println( fmt(" 当前内里 %s ,消耗内力  %s ->内里减去 结果 %s",killer["neili"],costNeili,killer["neili"] - costNeili) );

        if(  killer["neili"] - costNeili > 1 ){
            killer["neili"] -= costNeili;
            victim["qi"]+=recoverVal;

            btMsg+=fmt(" -> 结果:命中 恢复 %s 点气,目标气剩余 %s\n",recoverVal,victim["qi"]);

            batMsg = fmt("%s 恢复了 %s 点气血",victim["name"],recoverVal);
        }else{
            btMsg+=" -> 结果:未命中\n"
            batMsg = "结果能量不足!";
        }
//        println( fmt("能量消耗 %s ,当前能量 %s",costNeili,killer["neili"]) );



        //预防超量恢复
        if( victim["qi"] > victim["maxQi"] ){
            victim["qi"] = victim["maxQi"];
        }

    }else{

    }


    btMsg+=fmt(" -> 执行者状态 : 能量 %s - %s = %s",befNeili, befNeili - killer["neili"] ,befNeili - (befNeili - killer["neili"]));



    batMsg = fmt( "%s %s %s %s %s", kTitle, skillMsg, actType,vTitle,batMsg );

    kStr+=fmt("使出 %s(%s) -> %s\n",skName,skBufName,actType);


      println(kStr+vStr+btMsg);

        combatMessage+=batMsg;
//       if( kOb.query("isUser")  ){
//
//           kmsg = kOb.query("combatMessage");
//           kmsg+= batMsg;
//       }
//
//       if(vOb.query("isUser") ){
//            kmsg = vOb.query("combatMessage");
//           kmsg+= batMsg;
//       }





       if( victim["qi"] < 1  ){
            combatMessage+=fmt("%s(%s) 口吐鲜血,一口气上不来死了。",victim["name"],victim["qi"]);
//             if( kOb.query("isUser")  ){
//                   kOb.add("combat/reward/pot",20);
//                   combatMessage+=fmt("%s(%s) 口吐鲜血,一口气上不来死了。",victim["name"],victim["qi"]);
//             }
           return 1;
       }




//    println(fmt("%s(%s) -> %s(%s)",killer["name"],killer["qi"],victim["name"],victim["qi"]));



}

//是否能给目标设置Buf
static number canSetBuf(map victim,map buf){

    if( victim["effs"] && sizeof( victim["effs"] ) > 0 ){
        foreach(e in victim["effs"]){
            if( buf["type"]==e["type"] ) return 0;
        }
    }
    return 1;
}

static map* crRound(object k, object v){

    //回合唯一ID

    k.set("combatMessage",([]));
    v.set("combatMessage",([]));

    k.set("rGame/skills/attack","100001");
    k.set("rGame/skills/defense","100002");

     v.set("rGame/skills/attack","100003");
     v.set("rGame/skills/defense","100004");
     map sk1 = ({
        "rGame":({
            "skills":({
                "attack":"100003"
            })
        })

     });

          map sk2 = ({
             "rGame":({
                 "skills":({
                     "attack":"100002"
                 })
             })

          });

//     println("技能显示");
//     println(sk1["rGame"]["skills"]);




    map* que = ([
        ({
             "teamId":k.id(),
             "teamLeader":k,
             "name":k.query("name"),
             "qi":k.query("qi"),
             "maxQi":k.query("maxQi"),
             "neili":k.query("neili"),
             "maxNeili":k.query("maxNeili"),
             "str":k.query("str"),
             "int":k.query("int"),
             "dex":k.query("dex"),
             "combatExp":k.query("combatExp"),
             "skills":k.query("rGame/skills"),
             "con":k.query("con"),
             //虚拟站位 玩家vs玩家时  玩家始终在右边 6格
             "vPos":1,
             //物理站位
             "pPos":6

        }),
         ({
                     "teamId":k.id(),
                      "teamLeader":k,
                     "name":"老色鬼",
                     "qi":100,
                     "maxQi":100,
                      "neili":100,
                      "maxNeili":100,
                      "str":15,
                      "int":15,
                      "dex":15,
                      "combatExp":0,
                       "skills":sk1["rGame"]["skills"],
                      "con":15,
                       "vPos":4,
                       //物理站位
                       "pPos":5

          }),
         ({
             "teamId":v.id(),
              "teamLeader":v,
             "name":v.query("name"),
             "qi":v.query("qi"),
             "maxQi":v.query("maxQi"),
              "neili":v.query("neili"),
              "maxNeili":v.query("maxNeili"),
              "str":v.query("str"),
              "int":v.query("int"),
              "dex":v.query("dex"),
              "combatExp":v.query("combatExp"),
               "skills":v.query("rGame/skills"),
              "con":v.query("con"),
               "vPos":1,
               //物理站位
               "pPos":7
        }),

         ({
                     "teamId":v.id(),
                      "teamLeader":v,
                     "name":"赵灵儿",
                     "qi":100,
                     "maxQi":100,
                      "neili":100,
                      "maxNeili":100,
                      "str":15,
                      "int":15,
                      "dex":15,
                      "combatExp":0,
                       "skills":sk2["rGame"]["skills"],
                      "con":15,
                       "vPos":5,
                       //物理站位
                       "pPos":11
                })

    ]);

    return que;


}

//prev 上一回合数据
static map* nextRound(map *prev){
    //回合唯一ID
    map* nQue = ([]);
    foreach(k in prev){
          k["haveBeenAttack"]=0;
         if( k["qi"] > 0){
           nQue+=k;
         }
    }
    return nQue;
}

//获取对手阵营数据
static map* getEnemyLists(map killer,map* que){
    map* enemys  = ([]);
    foreach(e in que){
        if( e["teamId"]!=killer["teamId"] && e["qi"] > 0 ){
            enemys+=e;
        }
    }
    return enemys;
}
//获取我方成员数据
static map* getAllieLists(map killer,map* que){
    map* enemys  = ([]);
    foreach(e in que){
        if( e["teamId"]==killer["teamId"] && e["qi"] > 0 ){
            enemys+=e;
        }
    }
    return enemys;
}



//我方或者地方的前排
static map* getFront(map* enemys){
    map* enemyLists = ([]);
    foreach( e in enemys ){
        if( e["vPos"] > 0  && e["vPos"] < 4  ){
            enemyLists+=e;
        }
    }
    return enemyLists;
}

//我方或者地方的后排
static map* getBack(map* enemys){
    map* enemyLists = ([]);
    foreach( e in enemys ){
        if( e["vPos"] > 3  && e["vPos"] < 7  ){
            enemyLists+=e;
        }
    }
    return enemyLists;
}


static map getSkiData(map killer){
 //提取出技能
     var attackSk = killer["skills"]["attack"];
    if( !this::skillsConf ){
        println("skillConf没有数据啊!");
        return 1;
    }
    map skillData = this::skillsConf[attackSk];
    if( !skillData ){
        println(attackSk+" 没有找到技能文件");
    }
    return skillData;
}


//从对手集合中随机获取一个对手
static number getEnemyOfRandom(map* enemyQue){
    map enemy = enemyQue[ random(sizeof(enemyQue)-1)  ];
    return enemy;
}

static number selectEnemy(map killer,map* que,number currRound,string* combatMessage){

    map sk = getSkiData(killer);

    map buf = sk["bufs"][random(sizeof(sk["bufs"]))];
    var enemyLists = ([]);
     //1我方前排 2我方后排 3我方所有 4我自己(使用技能的人) 5敌方前排 6敌方后排 7敌方所有 8上一次攻击 9相同占位
    var emys ;

//    if( sizeof(emys) < 1 ) return 3;
    if( buf["findDomain"] == 5 ){//技能要求选择敌方前排
        emys = getEnemyLists(killer,que);
        enemyLists = getFront( emys );
    }else if(buf["findDomain"] == 1){//我方前排
        emys = getAllieLists(killer,que);
        enemyLists = getFront( emys );
    }else{
        emys = getEnemyLists(killer,que);
    }

//    if( killer["name"]=="大当家" ){
//        println(emys);
//        println(enemyLists);
//    }


    //    //对面都没人了...
    if( sizeof(emys) < 1 ) return 3;

    if( !enemyLists || sizeof(enemyLists) < 1 ) enemyLists+= emys[random(sizeof(emys)-1)];


    foreach(kv in enemyLists){
        this::rdKill(killer,sk,buf,kv,currRound,combatMessage);
        return 1;
    }
}



static number getReming(string id,map* que){
    number n=0;
    foreach( k in que ){
        if( k["teamId"]==id ) n++;
    }
    return n;
}


//每个回合 执行buf
static number evalBufs(map k){
    number n = sizeof(k["effs"]);
    if( n > 0 ){
//        for(number i=0;i < sizeof(k["effs"]);i++  ){
//            map e = k["effs"][i];
//            if( k["effs"][i]["duration"] > 0 ){
//                string s = fmt("%s 有 %s buf 剩余%s",k["name"],k["effs"][i]["type"],k["effs"][i]["duration"]);
//                println(s);
//                k["effs"][i]["duration"]--;
//            }
//        }

        foreach( e in k["effs"] ){
            e["duration"]--;
        }

        //过滤掉不需要的
        k["effs"] = filterArray( k["effs"],(e)->{
            return e["duration"] > 0 ;
        } );

//        println(k["effs"]);


    }

    return 1;

}

//能量恢复
static number recoverNeli(map *que){
    foreach(k in que){
        if( k["qi"] < 1 ) continue;

        if(  k["neili"] < k["maxNeili"] ){
             number recoverVal = k["maxNeili"] * 0.02;
             k["neili"]+=recoverVal;
        }

        if( k["neili"] > k["maxNeili"] ){
            println(fmt("当前能量 %s 最大能量 %s",k["neili"],k["maxNeili"]));
            k["neili"] = k["maxNeili"];
        }

    }
}

static number roundFight(object me, object victim){

    map kEntire = me.entityData();
    map vEntire = victim.entityData();

    //构建回合制调度器 交替回合制 所有人出手完成 算一回合

    //获取第n回合 战斗序列
    map* que =  this::crRound(me,victim);

    //如果是PVP 则是两个玩家
    object player = findPlayerObj(que);

    //提取队列分组ID
    string a1Id = me.id();
    string a2Id = victim.id();

    string* combatMessage = ([]);
    number rounCount = 1;
//    for(; sizeof(que) > 1 ;){
    for(  ;; ){
        foreach(k in que){
            if( k["qi"] < 1 ) continue;
             //是否有buf
            evalBufs(k);
            selectEnemy(k,que,rounCount,combatMessage);
        }
        //恢复能量
        recoverNeli(que);

        rounCount++;
        que = nextRound( que );
        if( getReming(a1Id,que) < 1 || getReming(a2Id,que) < 1  ) break;

    }

    println(combatMessage);
    //把战斗记录挂载玩家身上
    player.set("combatMessage",combatMessage);
    println( fmt("%s 回合后 剩下的队伍%s",rounCount,toJsonStr(que)) );

}


static object findPlayerObj(map* que){
    foreach( e in que ){
        if( e["teamLeader"].query("isUser") ){
            return e["teamLeader"];
        }
    }
    return 0;
}



static number testCron(string param){
    println("被计划调用咯"+param);
}
posted @ 2025-06-04 07:55  方东信  阅读(19)  评论(0)    收藏  举报