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) {
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));

View File

@ -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; i<a.at->type; i++) if(a+i == b) return i;
return NODIR;
}
EX int create_path() {
map<cell*, bowpoint> scores;
scores[cwt.at] = bowpoint();
scores[cwt.at].last = movei(cwt.at, STAY);
map<cell*, bowscore> 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<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;
}