自走棋

有战斗动画

适配设备:Pro

作者:kylin

下载量:46 · 点赞:0

可信源码风险提示:保存或下载前请阅读源码和权限声明。
SHA-2568c2a562fe2b01e42ea3e5dec3ad5f5bb914c68b7907e97b718322457fec44940
var SAVE_KEY = 'auto_chess_v3';
var g = ui.signal({
  page: 'home',
  gold: 10,
  hp: 100,
  round: 1,
  streak: 0,
  phase: 'prepare',
  shop: [],
  shopLevel: 1,
  myUnits: [],
  enemies: [],
  bench: [],
  bag: [],
  logs: ['欢迎'],
  selCell: null,
  selBench: null,
  detailHero: null,
  compPage: 0,
  winCount: 0
});

function clone(o) {
  if (o === null || typeof o !== 'object') return o;
  if (Array.isArray(o)) {
    var a = [];
    for (var i = 0; i < o.length; i++) a.push(clone(o[i]));
    return a;
  }
  var n = {};
  for (var k in o) if (o.hasOwnProperty(k)) n[k] = clone(o[k]);
  return n;
}

function update(fn) {
  var s = clone(g.get());
  fn(s);
  g.set(s);
}

var HEROES = [
  { id: 'h1', n: '诺手', r: '帝国', j: '战士', c: 1, hp: 650, a: 55, rg: 1, s: '流血:普攻附带5%最大生命伤害' },
  { id: 'h2', n: '德玛', r: '帝国', j: '坦克', c: 1, hp: 850, a: 40, rg: 1, s: '大反派:优先攻击最高血量' },
  { id: 'h3', n: '寒冰', r: '极地', j: '射手', c: 1, hp: 450, a: 60, rg: 3, s: '冰冻:25%冰冻敌人' },
  { id: 'h4', n: '大树', r: '森林', j: '坦克', c: 1, hp: 900, a: 35, rg: 1, s: '回春:每回合回血' },
  { id: 'h5', n: '小法', r: '约德尔', j: '法师', c: 2, hp: 450, a: 80, rg: 3, s: '爆发:优先最低血量' },
  { id: 'h6', n: '劫', r: '忍者', j: '刺客', c: 2, hp: 550, a: 75, rg: 1, s: '影分身:30%双倍伤害' },
  { id: 'h7', n: '奶妈', r: '星神', j: '辅助', c: 2, hp: 500, a: 30, rg: 2, s: '星落:治疗最低队友' },
  { id: 'h8', n: '狐狸', r: '星神', j: '法师', c: 2, hp: 480, a: 65, rg: 2, s: '宝珠:弹射伤害' },
  { id: 'h9', n: '卡特', r: '帝国', j: '刺客', c: 3, hp: 600, a: 70, rg: 1, s: '莲华:50%溅射伤害' },
  { id: 'h10', n: '奥拉夫', r: '极地', j: '战士', c: 3, hp: 750, a: 65, rg: 1, s: '诸神黄昏:攻击两次' },
  { id: 'h11', n: '火男', r: '恶魔', j: '法师', c: 3, hp: 550, a: 75, rg: 3, s: '烈焰:范围溅射' },
  { id: 'h12', n: '亚索', r: '浪人', j: '战士', c: 4, hp: 700, a: 70, rg: 1, s: '狂风绝息斩:无视护甲' },
  { id: 'h13', n: '剑圣', r: '浪人', j: '刺客', c: 3, hp: 600, a: 80, rg: 1, s: '阿尔法突袭:闪避普攻' },
  { id: 'h14', n: '光辉', r: '帝国', j: '法师', c: 4, hp: 500, a: 90, rg: 4, s: '终极闪光:贯穿直线' },
  { id: 'h15', n: '大虫子', r: '虚空', j: '坦克', c: 3, hp: 950, a: 45, rg: 1, s: '破裂:降低敌方防御' },
  { id: 'h16', n: '卡莎', r: '虚空', j: '射手', c: 4, hp: 600, a: 85, rg: 3, s: '虚空突袭:获得护盾' },
  { id: 'h17', n: '挖掘机', r: '虚空', j: '战士', c: 2, hp: 700, a: 50, rg: 1, s: '遁地:恢复生命' },
  { id: 'h18', n: '螳螂', r: '虚空', j: '刺客', c: 1, hp: 500, a: 60, rg: 1, s: '品尝恐惧:孤立无援伤害翻倍' },
  { id: 'h19', n: '龙王', r: '星神', j: '法师', c: 5, hp: 800, a: 100, rg: 4, s: '星弦高落:全屏伤害' },
  { id: 'h20', n: '死歌', r: '亡灵', j: '法师', c: 5, hp: 700, a: 110, rg: 5, s: '安魂曲:轰炸所有敌人' }
];

var EQUIPS = [
  { id: 'e1', n: '大剑', a: 20, hp: 0 },
  { id: 'e2', n: '反曲弓', a: 10, hp: 100 },
  { id: 'e3', n: '大棒', a: 15, hp: 80 },
  { id: 'e4', n: '腰带', a: 0, hp: 250 },
  { id: 'e5', n: '斗篷', a: 5, hp: 180 },
  { id: 'e6', n: '眼泪', a: 8, hp: 120 }
];

var battleTimer = null;

function loadData() {
  try {
    var d = settingsStorage.getItem(SAVE_KEY);
    if (d) {
      var p = JSON.parse(d);
      update(function(s) { s.winCount = p.w || 0; });
    }
  } catch(e) {}
}

function saveData() {
  try {
    var s = g.get();
    settingsStorage.setItem(SAVE_KEY, JSON.stringify({ w: s.winCount }));
  } catch(e) {}
}

function rollShop() {
  update(function(s) {
    var pool = HEROES.filter(function(h) { return h.c <= s.shopLevel + 1; });
    var nShop = [];
    for (var i = 0; i < 3; i++) nShop.push(pool[Math.floor(Math.random() * pool.length)]);
    s.shop = nShop;
  });
}

function getSynergies(units) {
  var j = {}, r = {};
  for (var i = 0; i < units.length; i++) {
    j[units[i].j] = (j[units[i].j] || 0) + 1;
    r[units[i].r] = (r[units[i].r] || 0) + 1;
  }
  var t = [];
  for (var k in j) if (j[k] >= 2) t.push(k + j[k]);
  for (var k in r) if (r[k] >= 2) t.push(k + r[k]);
  return t.length ? t.join(' ') : '无';
}

function applySynergy(s) {
  var j = {}, r = {};
  for (var i = 0; i < s.myUnits.length; i++) {
    j[s.myUnits[i].j] = (j[s.myUnits[i].j] || 0) + 1;
    r[s.myUnits[i].r] = (r[s.myUnits[i].r] || 0) + 1;
  }
  var atkAdd = 0, hpAdd = 0;
  if (j['战士'] >= 2) atkAdd += 15;
  if (j['法师'] >= 2) atkAdd += 20;
  if (j['坦克'] >= 2) hpAdd += 200;
  if (j['刺客'] >= 2) atkAdd += 20;
  if (r['帝国'] >= 2) atkAdd += 25;
  if (r['极地'] >= 2) hpAdd += 150;
  if (r['星神'] >= 2) hpAdd += 150;
  if (r['虚空'] >= 2) atkAdd += 30;
  if (r['约德尔'] >= 2) hpAdd += 100;
  for (var i = 0; i < s.myUnits.length; i++) {
    s.myUnits[i].a += atkAdd;
    s.myUnits[i].hp += hpAdd;
    s.myUnits[i].maxHp += hpAdd;
  }
}

function buyHero(idx) {
  update(function(s) {
    if (s.phase === 'battle' || !s.shop[idx]) return;
    var h = s.shop[idx];
    if (s.gold < h.c) { s.logs.push('金币不足'); return; }
    if (s.bench.length >= 4) { s.logs.push('待命区已满'); return; }
    
    var same = s.bench.filter(function(u) { return u.id === h.id && u.star === 1; });
    if (same.length >= 2) {
      same[0].star = 2;
      same[0].hp = h.hp * 2;
      same[0].maxHp = h.hp * 2;
      same[0].a = h.a + Math.floor(h.a * 0.8);
      s.bench = s.bench.filter(function(u) { return u !== same[1]; });
      s.logs.push(h.n + '升至2星');
    } else {
      s.bench.push({
        id: h.id, n: h.n, r: h.r, j: h.j, c: h.c, star: 1,
        hp: h.hp, maxHp: h.hp, a: h.a, rg: h.rg, s: h.s
      });
    }
    s.gold -= h.c;
    s.shop[idx] = null;
  });
}

function selBenchUnit(idx) {
  update(function(s) {
    if (s.phase === 'battle') return;
    if (s.bench[idx]) {
      s.selBench = idx;
      s.selCell = null;
    }
  });
}

function clickCell(x, y) {
  update(function(s) {
    if (s.phase === 'battle') return;
    
    var unitIdx = -1;
    for (var i = 0; i < s.myUnits.length; i++) {
      if (s.myUnits[i].x === x && s.myUnits[i].y === y) { unitIdx = i; break; }
    }

    if (s.selBench !== null) {
      if (unitIdx !== -1) { s.logs.push('位置被占'); return; }
      var bUnit = s.bench.splice(s.selBench, 1)[0];
      bUnit.x = x;
      bUnit.y = y;
      s.myUnits.push(bUnit);
      s.selBench = null;
      s.selCell = null;
    } else if (unitIdx !== -1) {
      s.selCell = { x: x, y: y };
      s.selBench = null;
    } else {
      s.selCell = { x: x, y: y };
    }
  });
}

function sellSelected() {
  update(function(s) {
    if (s.phase === 'battle' || !s.selCell) return;
    for (var i = 0; i < s.myUnits.length; i++) {
      if (s.myUnits[i].x === s.selCell.x && s.myUnits[i].y === s.selCell.y) {
        s.gold += s.myUnits[i].c;
        s.logs.push('出售获得' + s.myUnits[i].c + '金');
        s.myUnits.splice(i, 1);
        break;
      }
    }
    s.selCell = null;
  });
}

function buyEquip() {
  update(function(s) {
    if (s.gold < 3 || s.phase === 'battle') return;
    s.bag.push(EQUIPS[Math.floor(Math.random() * EQUIPS.length)]);
    s.gold -= 3;
    s.logs.push('获得装备');
  });
}

function startBattle() {
  var state = g.get();
  if (state.phase === 'battle' || !state.myUnits.length) return;
  
  update(function(s) {
    s.phase = 'battle';
    s.enemies = [];
    s.selCell = null;
    s.selBench = null;
    
    var count = Math.min(6, 1 + Math.floor(s.round / 2));
    for (var i = 0; i < count; i++) {
      var h = HEROES[Math.floor(Math.random() * HEROES.length)];
      var row = Math.floor(Math.random() * 3);
      var col = Math.floor(Math.random() * 4);
      var dup = false;
      for (var j = 0; j < s.enemies.length; j++) {
        if (s.enemies[j].x === col && s.enemies[j].y === row) { dup = true; break; }
      }
      if (!dup) {
        s.enemies.push({
          id: h.id, n: h.n, r: h.r, j: h.j, star: 1, team: 1, x: col, y: row,
          hp: h.hp + s.round * 50, maxHp: h.hp + s.round * 50,
          a: h.a + s.round * 5, rg: h.rg, s: h.s, frozen: 0
        });
      }
    }
    
    for (var i = 0; i < s.myUnits.length; i++) {
      s.myUnits[i].team = 0;
      s.myUnits[i].frozen = 0;
    }
    applySynergy(s);
    s.logs.push('战斗开始');
  });
  
  if (battleTimer) clearTimeout(battleTimer);
  battleTimer = setTimeout(battleTick, 500);
}

function battleTick() {
  var s = g.get();
  if (s.phase !== 'battle') return;

  var all = s.myUnits.concat(s.enemies);
  var aliveM = 0, aliveE = 0, i, j;

  for (i = 0; i < s.myUnits.length; i++) if (s.myUnits[i].hp > 0) aliveM++;
  for (i = 0; i < s.enemies.length; i++) if (s.enemies[i].hp > 0) aliveE++;

  if (!aliveM || !aliveE) {
    update(function(st) {
      st.phase = 'prepare';
      if (aliveM) {
        var inc = 5 + st.streak;
        st.gold += inc;
        st.streak++;
        st.winCount++;
        st.round++;
        st.logs.push('胜利 +' + inc + '金');
      } else {
        st.hp -= 10;
        st.streak = 0;
        st.logs.push('失败 -10血');
      }
      for (i = 0; i < st.myUnits.length; i++) st.myUnits[i].hp = st.myUnits[i].maxHp;
      st.enemies = [];
    });
    saveData();
    return;
  }

  update(function(st) {
    var all = st.myUnits.concat(st.enemies);
    for (var i = 0; i < all.length; i++) {
      var u = all[i];
      if (u.hp <= 0) continue;
      if (u.frozen > 0) { u.frozen--; continue; }

      var targets = u.team === 0 ? st.enemies : st.myUnits;
      var target = null, minD = 999;

      for (var j = 0; j < targets.length; j++) {
        if (targets[j].hp > 0) {
          var d = Math.abs(u.x - targets[j].x) + Math.abs(u.y - targets[j].y);
          if (d < minD) { minD = d; target = targets[j]; }
        }
      }
      if (!target) continue;

      if (minD <= u.rg) {
        var dmg = u.a;
        if (u.id === 'h6' && Math.random() < 0.3) dmg *= 2;
        target.hp -= dmg;
        if (u.id === 'h1') target.hp -= Math.floor(target.maxHp * 0.05);
        if (u.id === 'h3' && Math.random() < 0.25) target.frozen = 1;
        if (target.hp < 0) target.hp = 0;
      } else {
        var nx = u.x, ny = u.y;
        if (u.x < target.x) nx++; else if (u.x > target.x) nx--;
        else if (u.y < target.y) ny++; else if (u.y > target.y) ny--;
        var occ = false;
        for (var j = 0; j < all.length; j++) {
          if (all[j] !== u && all[j].hp > 0 && all[j].x === nx && all[j].y === ny) { occ = true; break; }
        }
        if (!occ && nx >= 0 && nx < 4 && ny >= 0 && ny < 6) { u.x = nx; u.y = ny; }
      }
    }
  });

  battleTimer = setTimeout(battleTick, 500);
}

function goPage(p) {
  update(function(s) {
    s.page = p;
    if (p === 'home') {
      s.phase = 'prepare';
      s.myUnits = []; s.enemies = []; s.bench = [];
      s.selCell = null; s.selBench = null;
    }
  });
}

function resetGame() {
  if (battleTimer) clearTimeout(battleTimer);
  update(function(s) {
    s.round = 1; s.gold = 10; s.hp = 100; s.streak = 0; s.phase = 'prepare';
    s.myUnits = []; s.enemies = []; s.bench = []; s.bag = [];
    s.logs = ['重置']; s.selCell = null; s.selBench = null;
  });
  rollShop();
}

loadData();
rollShop();

ui.showHeader(false);

ui.render(function() {
  var s = g.get();

  if (s.page === 'home') {
    return ui.column([
      ui.text('', { id: 'h_s1', size: 50, lines: 1 }),
      ui.text('自走棋大师', { id: 'h_t1', size: 32, lines: 1, color: '#f1c40f', align: 'center' }),
      ui.text('最高连胜: ' + s.winCount, { id: 'h_t2', size: 16, lines: 1, color: '#1abc9c', align: 'center' }),
      ui.text('', { id: 'h_s2', size: 30, lines: 1 }),
      ui.stack([
        ui.button('开始游戏', function() { goPage('game'); }, { id: 'h_b1', x: 68, y: 0, width: 200, height: 50, lines: 1, background: '#27ae60', color: '#fff' }),
        ui.button('英雄图鉴', function() { update(function(st){ st.page = 'compendium'; st.compPage = 0; }); }, { id: 'h_b2', x: 68, y: 65, width: 200, height: 50, lines: 1, background: '#2980b9', color: '#fff' }),
        ui.button('退出游戏', function() { if (typeof script !== 'undefined' && script.exit) script.exit(); }, { id: 'h_b3', x: 68, y: 130, width: 200, height: 50, lines: 1, background: '#7f8c8d', color: '#fff' })
      ], { id: 'h_st', height: 180 })
    ], { id: 'h_col', gap: 0 });
  }

  if (s.page === 'compendium') {
    var b = [];
    var start = s.compPage * 6;
    for (var i = 0; i < 6; i++) {
      var idx = start + i;
      if (idx >= HEROES.length) break;
      var h = HEROES[idx];
      b.push(ui.button(h.n + ' ' + h.c + '费', (function(hero) {
        return function() { update(function(st){ st.page = 'detail'; st.detailHero = hero; }); };
      })(h), {
        id: 'c_b' + i, x: (i % 2) * 164 + 4, y: Math.floor(i / 2) * 60, width: 160, height: 50,
        background: '#2c3e50', color: '#fff'
      }));
    }
    return ui.column([
      ui.text('英雄图鉴', { id: 'c_t', size: 22, lines: 1, color: '#f1c40f', align: 'center' }),
      ui.stack(b, { id: 'c_s', height: 186 }),
      ui.stack([
        ui.button('上一页', function() { update(function(st){ if(st.compPage>0) st.compPage--; }); }, { id: 'c_p1', x: 10, y: 0, width: 100, height: 40, background: '#34495e', color: '#fff' }),
        ui.button('返回', function() { goPage('home'); }, { id: 'c_p2', x: 118, y: 0, width: 100, height: 40, background: '#7f8c8d', color: '#fff' }),
        ui.button('下一页', function() { update(function(st){ if((st.compPage+1)*6<HEROES.length) st.compPage++; }); }, { id: 'c_p3', x: 226, y: 0, width: 100, height: 40, background: '#34495e', color: '#fff' })
      ], { id: 'c_n', height: 50 })
    ], { id: 'c_col', gap: 10 });
  }

  if (s.page === 'detail') {
    var h = s.detailHero;
    return ui.column([
      ui.text(h.n + ' (' + h.c + '费)', { id: 'd_t', size: 24, lines: 1, color: '#f1c40f', align: 'center' }),
      ui.text('种族:' + h.r + ' 职业:' + h.j, { id: 'd_i', size: 16, lines: 1, color: '#3498db', align: 'center' }),
      ui.text('生命:' + h.hp + ' 攻击:' + h.a, { id: 'd_s', size: 16, lines: 1, color: '#2ecc71', align: 'center' }),
      ui.text('技能描述', { id: 'd_st', size: 16, lines: 1, color: '#e67e22', align: 'center' }),
      ui.text(h.s, { id: 'd_sk', size: 16, lines: 3, color: '#ecf0f1', align: 'center' }),
      ui.stack([
        ui.button('返回图鉴', function() { update(function(st){ st.page = 'compendium'; }); }, { id: 'd_b', x: 68, y: 0, width: 200, height: 50, background: '#7f8c8d', color: '#fff' })
      ], { id: 'd_n', height: 60 })
    ], { id: 'd_col', gap: 15 });
  }

  if (s.page === 'bag') {
    var eb = [];
    for (var i = 0; i < 8; i++) {
      var e = s.bag[i];
      eb.push(ui.button(e ? e.n : '空', function(){}, {
        id: 'e_b' + i, x: (i % 2) * 164 + 4, y: Math.floor(i / 2) * 50, width: 160, height: 40,
        background: e ? '#d35400' : '#1e1e1e', color: '#fff'
      }));
    }
    return ui.column([
      ui.text('装备背包', { id: 'b_t', size: 22, lines: 1, color: '#f1c40f', align: 'center' }),
      ui.stack(eb, { id: 'b_s', height: 200 }),
      ui.stack([
        ui.button('返回游戏', function() { goPage('game'); }, { id: 'b_b', x: 68, y: 0, width: 200, height: 50, background: '#7f8c8d', color: '#fff' })
      ], { id: 'b_n', height: 60 })
    ], { id: 'b_col', gap: 10 });
  }

  if (s.page === 'game') {
    var cells = [];
    for (var i = 0; i < 24; i++) {
      var r = Math.floor(i / 4), c = i % 4;
      var unit = null;
      for (var j = 0; j < s.myUnits.length; j++) if (s.myUnits[j].x === c && s.myUnits[j].y === r && s.myUnits[j].hp > 0) { unit = s.myUnits[j]; break; }
      if (!unit) for (var j = 0; j < s.enemies.length; j++) if (s.enemies[j].x === c && s.enemies[j].y === r && s.enemies[j].hp > 0) { unit = s.enemies[j]; break; }

      var txt = '';
      var bg = '#1e1e1e';
      if (unit) {
        txt = unit.n + (unit.star > 1 ? '2' : '') + (unit.frozen ? '*' : '');
        bg = unit.team === 0 ? '#2980b9' : '#c0392b';
      }
      if (s.selCell && s.selCell.x === c && s.selCell.y === r) bg = '#f39c12';

      cells.push(ui.button(txt, (function(x, y) { return function() { clickCell(x, y); }; })(c, r), {
        id: 'g_c' + i, x: c * 84, y: r * 42, width: 84, height: 42, lines: 1, background: bg, color: '#fff'
      }));
    }

    var shop = [];
    for (var i = 0; i < 3; i++) {
      var h = s.shop[i];
      shop.push(ui.button(h ? h.n + '(' + h.c + ')' : '空', (function(idx) { return function() { buyHero(idx); }; })(i), {
        id: 'g_s' + i, x: i * 108, y: 0, width: 100, height: 32, lines: 1, background: h ? '#2980b9' : '#2c3e50', color: '#fff'
      }));
    }

    var benchBtns = [];
    for (var i = 0; i < 4; i++) {
      var u = s.bench[i];
      benchBtns.push(ui.button(u ? u.n : '空', (function(idx) { return function() { selBenchUnit(idx); }; })(i), {
        id: 'g_b' + i, x: i * 80, y: 0, width: 76, height: 30, lines: 1, background: u ? (s.selBench === i ? '#f39c12' : '#16a085') : '#1e1e1e', color: '#fff'
      }));
    }

    return ui.column([
      ui.text('R' + s.round + ' 金' + s.gold + ' 血' + s.hp + ' ' + getSynergies(s.myUnits), { id: 'g_t', size: 14, lines: 1, color: '#f1c40f', align: 'center' }),
      ui.stack(cells, { id: 'g_grid', height: 252 }),
      ui.text(s.logs[s.logs.length - 1], { id: 'g_l', size: 12, lines: 1, color: '#ecf0f1', align: 'center' }),
      ui.stack(shop, { id: 'g_shop', height: 34 }),
      ui.stack(benchBtns, { id: 'g_bench', height: 32 }),
      ui.stack([
        ui.button('刷新', function() { update(function(st){ if(st.gold>=2 && st.phase!=='battle'){ st.gold-=2; g.set(st); rollShop(); } }); }, { id: 'g_o1', x: 0, y: 0, width: 80, height: 32, background: '#8e44ad', color: '#fff' }),
        ui.button('买装', buyEquip, { id: 'g_o2', x: 84, y: 0, width: 80, height: 32, background: '#d35400', color: '#fff' }),
        ui.button('出售', sellSelected, { id: 'g_o3', x: 168, y: 0, width: 80, height: 32, background: '#c0392b', color: '#fff' }),
        ui.button('背包', function() { goPage('bag'); }, { id: 'g_o4', x: 252, y: 0, width: 80, height: 32, background: '#34495e', color: '#fff' })
      ], { id: 'g_ops', height: 34 }),
      ui.stack([
        ui.button('开战', startBattle, { id: 'g_f', x: 0, y: 0, width: 160, height: 32, background: '#c0392b', color: '#fff' }),
        ui.button('重置', resetGame, { id: 'g_r', x: 168, y: 0, width: 80, height: 32, background: '#7f8c8d', color: '#fff' }),
        ui.button('返回', function() { goPage('home'); }, { id: 'g_h', x: 252, y: 0, width: 80, height: 32, background: '#34495e', color: '#fff' })
      ], { id: 'g_bts', height: 34 })
    ], { id: 'g_col', gap: 2 });
  }
});