1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2025-06-26 15:12:48 +00:00

crossbow:: mimics shoot too

This commit is contained in:
Zeno Rogue 2023-10-27 23:26:03 +02:00
parent 9da8206a9f
commit 41e28c34b2
2 changed files with 92 additions and 28 deletions

View File

@ -2626,22 +2626,22 @@ void celldrawer::add_map_effects() {
} }
if(1) { 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; hyperpoint h0 = C0, t0 = Hypc, h1 = C0, t1 = Hypc;
bool birth = false; bool birth = m.first;
if(m.last.d != STAY) { if(!birth) {
ld d = cellgfxdist(c, m.last.d) / 2; ld d = cellgfxdist(c, m.prev.spin) / 2;
h0 = ddspin(c, m.last.d) * xpush0(d); h0 = ddspin(c, m.prev.spin) * xpush0(d);
t0 = ddspin(c, m.last.d) * xpush(d) * xtangent(-d*2); t0 = ddspin(c, m.prev.spin) * xpush(d) * xtangent(-d*2);
} }
else birth = true; else birth = true;
if(m.next.d != STAY) { if(!m.last) {
ld d = cellgfxdist(c, m.next.d) / 2; ld d = cellgfxdist(c, m.next.spin) / 2;
h1 = ddspin(c, m.next.d) * xpush0(d); h1 = ddspin(c, m.next.spin) * xpush0(d);
t1 = ddspin(c, m.next.d) * xpush(d) * xtangent(-d*2); t1 = ddspin(c, m.next.spin) * xpush(d) * xtangent(-d*2);
} }
ld t = frac(ptick(PURE?500:250)); ld t = frac(ptick(PURE?500:250));

View File

@ -38,10 +38,17 @@ EX bool crossbow_mode() { return weapon == wCrossbow; }
#if HDR #if HDR
struct bowpoint { struct bowpoint {
cellwalker prev, next;
bool first, last;
bool copied;
bool mirrored;
bowpoint() {}
};
struct bowscore {
int total; int total;
movei last, next, lastun; cellwalker last;
cell *con; int turns;
bowpoint() : last(nullptr), next(nullptr), lastun(nullptr) { total = 0; }
}; };
#endif #endif
@ -56,14 +63,20 @@ EX int loading_time() {
} }
EX bool blocks(cell *c) { 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; return false;
} }
EX int qadd(cellwalker a, cellwalker b) {
hassert(a.at == b.at);
for(int i=0; i<a.at->type; i++) if(a+i == b) return i;
return NODIR;
}
EX int create_path() { EX int create_path() {
map<cell*, bowpoint> scores; map<cell*, bowscore> scores;
scores[cwt.at] = bowpoint(); scores[cwt.at].total = 0;
scores[cwt.at].last = movei(cwt.at, STAY);
int best_score = -1; cell* best_score_at = cwt.at; int best_score = -1; cell* best_score_at = cwt.at;
@ -71,38 +84,89 @@ EX int create_path() {
cell *c1 = target_at[c->cpdist]; cell *c1 = target_at[c->cpdist];
if(c1 && c != c1) continue; if(c1 && c != c1) continue;
if(c == c1) { best_score = -1; } if(c == c1) { best_score = -1; }
bowpoint best; bowscore best;
best.total = -1; best.total = -1;
forCellIdEx(c1, i, c) if(c1->cpdist < c->cpdist && scores.count(c1)) { forCellIdEx(c1, i, c) if(c1->cpdist < c->cpdist && scores.count(c1)) {
auto last = scores[c1]; auto& last = scores[c1];
int ntotal = last.total; 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(inmirror(c)) cw2 = mirror::reflect(cw2);
if(blocks(cw2.peek())) continue; if(blocks(cw2.peek())) continue;
if(cw2.at->monst) { ntotal += 10000; ntotal += 1280 >> c->cpdist; } if(cw2.at->monst) { ntotal += 10000; ntotal += 1280 >> c->cpdist; }
ntotal += 2; ntotal += 2;
int dir = 0;
if(c->cpdist > 1) { 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(d != c1->type / 2) {
if(style == cbGeodesic) ntotal--; if(style == cbGeodesic) ntotal--;
if(style == cbBull) continue; 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); best.total = max(best.total, ntotal);
} }
if(best.total > best_score) { best_score = best.total; best_score_at = c; } if(best.total > best_score) { best_score = best.total; best_score_at = c; }
if(best.total > -1) scores[c] = best; if(best.total > -1) scores[c] = best;
} }
bowpath.clear();
if(best_score == -1) return best_score; 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<int> 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<cellwalker> bolts = { cwt };
for(auto m: mirror::mirrors) bolts.push_back(m.second);
set<cell*> broken_mirrors;
for(auto d: dirseq) {
bool first = bowpath.empty();
vector<cellwalker> nbolts;
set<cell*> 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<pair<int, cellwalker>> 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; return best_score;
} }