diff --git a/celldrawer.cpp b/celldrawer.cpp index fcfcf1fb..7ba339ef 100644 --- a/celldrawer.cpp +++ b/celldrawer.cpp @@ -2626,22 +2626,22 @@ void celldrawer::add_map_effects() { } if(1) { - for(auto& m: bow::last_bowpath) if(m.next.s == c) { + for(auto& m: bow::last_bowpath) if(m.next.at == c) { hyperpoint h0 = C0, t0 = Hypc, h1 = C0, t1 = Hypc; - bool birth = false; + bool birth = m.first; - if(m.last.d != STAY) { - ld d = cellgfxdist(c, m.last.d) / 2; - h0 = ddspin(c, m.last.d) * xpush0(d); - t0 = ddspin(c, m.last.d) * xpush(d) * xtangent(-d*2); + if(!birth) { + ld d = cellgfxdist(c, m.prev.spin) / 2; + h0 = ddspin(c, m.prev.spin) * xpush0(d); + t0 = ddspin(c, m.prev.spin) * xpush(d) * xtangent(-d*2); } else birth = true; - if(m.next.d != STAY) { - ld d = cellgfxdist(c, m.next.d) / 2; - h1 = ddspin(c, m.next.d) * xpush0(d); - t1 = ddspin(c, m.next.d) * xpush(d) * xtangent(-d*2); + if(!m.last) { + ld d = cellgfxdist(c, m.next.spin) / 2; + h1 = ddspin(c, m.next.spin) * xpush0(d); + t1 = ddspin(c, m.next.spin) * xpush(d) * xtangent(-d*2); } ld t = frac(ptick(PURE?500:250)); diff --git a/crossbow.cpp b/crossbow.cpp index ec4b1ce6..bb9d7777 100644 --- a/crossbow.cpp +++ b/crossbow.cpp @@ -38,10 +38,17 @@ EX bool crossbow_mode() { return weapon == wCrossbow; } #if HDR struct bowpoint { + cellwalker prev, next; + bool first, last; + bool copied; + bool mirrored; + bowpoint() {} + }; + +struct bowscore { int total; - movei last, next, lastun; - cell *con; - bowpoint() : last(nullptr), next(nullptr), lastun(nullptr) { total = 0; } + cellwalker last; + int turns; }; #endif @@ -56,14 +63,20 @@ EX int loading_time() { } EX bool blocks(cell *c) { - if(isWall(c) && c->wall != waMirrorWall) return true; + if(isWall(c) && !among(c->wall, waMirrorWall, waMirror, waCloud)) return true; + // if(c->monst && isMultitile(c->monst)) return true; return false; } +EX int qadd(cellwalker a, cellwalker b) { + hassert(a.at == b.at); + for(int i=0; itype; i++) if(a+i == b) return i; + return NODIR; + } + EX int create_path() { - map scores; - scores[cwt.at] = bowpoint(); - scores[cwt.at].last = movei(cwt.at, STAY); + map scores; + scores[cwt.at].total = 0; int best_score = -1; cell* best_score_at = cwt.at; @@ -71,38 +84,89 @@ EX int create_path() { cell *c1 = target_at[c->cpdist]; if(c1 && c != c1) continue; if(c == c1) { best_score = -1; } - bowpoint best; + bowscore best; best.total = -1; forCellIdEx(c1, i, c) if(c1->cpdist < c->cpdist && scores.count(c1)) { - auto last = scores[c1]; + auto& last = scores[c1]; int ntotal = last.total; - auto cw2 = cellwalker(c, i); + auto ocw2 = cellwalker(c, i); + auto cw2 = ocw2; if(inmirror(c)) cw2 = mirror::reflect(cw2); if(blocks(cw2.peek())) continue; if(cw2.at->monst) { ntotal += 10000; ntotal += 1280 >> c->cpdist; } ntotal += 2; + int dir = 0; if(c->cpdist > 1) { - int d = abs(szgmod(last.lastun.d - c->c.spin(i), c1->type)); + dir = qadd(last.last, ocw2+wstep); + int d = abs(szgmod(dir, c1->type)); if(d != c1->type / 2) { if(style == cbGeodesic) ntotal--; if(style == cbBull) continue; } } - if(ntotal > best.total) { best.total = ntotal; best.lastun = movei(c, i); best.last = movei(cw2.at, cw2.spin); best.con = c1; best.next = movei(cw2.at, STAY); } + else { + dir = qadd(cwt, ocw2+wstep); + } + if(ntotal > best.total) { + best.total = ntotal; + best.last = ocw2; + best.turns = dir; + } best.total = max(best.total, ntotal); } if(best.total > best_score) { best_score = best.total; best_score_at = c; } if(best.total > -1) scores[c] = best; } - bowpath.clear(); if(best_score == -1) return best_score; - while(best_score_at != cwt.at) { - bowpath.push_back(scores[best_score_at]); best_score_at = bowpath.back().con; scores[best_score_at].next = bowpath.back().last.rev(); - } - bowpath.push_back(scores[best_score_at]); - reverse(bowpath.begin(), bowpath.end()); + vector dirseq = { NODIR }; + while(best_score_at != cwt.at) { + auto& at = scores[best_score_at]; + dirseq.push_back(at.turns); + best_score_at = at.last.peek(); + } + reverse(dirseq.begin(), dirseq.end()); + + println(hlog, "dirseq = ", dirseq); + + bowpath.clear(); + vector bolts = { cwt }; + for(auto m: mirror::mirrors) bolts.push_back(m.second); + + set broken_mirrors; + + for(auto d: dirseq) { + bool first = bowpath.empty(); + vector nbolts; + set next_broken_mirrors = broken_mirrors; + for(auto bolt: bolts) { + bowpath.emplace_back(); + auto& p = bowpath.back(); + p.prev = bolt; + p.first = first; + if(d == NODIR || blocks(bolt.at)) { p.next = bolt; p.last = true; } + else { + if(inmirror(bolt.at) || bolt.at->wall == waMirrorWall) bolt = mirror::reflect(bolt); + bolt += d; + p.next = bolt; p.last = false; + bolt += wstep; + if(among(bolt.at->wall, waCloud, waMirror) && !broken_mirrors.count(bolt.at)) { + auto &mir = mirror::mirrors; + vector> bmir; + swap(mir, bmir); + mirror::createHere(bolt, 0); + swap(mir, bmir); + for(auto b: bmir) nbolts.push_back(b.second); + next_broken_mirrors.insert(bolt.at); + } + nbolts.push_back(bolt); + } + } + bolts = nbolts; + broken_mirrors = next_broken_mirrors; + } + return best_score; }