diff --git a/complex.cpp b/complex.cpp index 8b706203..edf62f4e 100644 --- a/complex.cpp +++ b/complex.cpp @@ -2620,14 +2620,17 @@ namespace dragon { } namespace sword { - array angle; + int sword_angles; + + array dir; void possible_divisor(int s) { sword_angles *= s / gcd(sword_angles, s); } void determine_sword_angles() { sword_angles = 2; - if(IRREGULAR) sword_angles = 840; + if(DIM == 3) sword_angles = 1; + else if(IRREGULAR) sword_angles = 840; else if(binarytiling) sword_angles = 42; else if(archimedean) { if(!PURE) possible_divisor((BITRUNCATED ? 2 : 1) * isize(arcm::current.faces)); @@ -2639,7 +2642,7 @@ namespace sword { } } - cell *pos(cell *c, int s) { + cell *pos2(cell *c, int s) { int t = c->type; s *= 2; s += sword_angles/t; @@ -2650,12 +2653,26 @@ namespace sword { return c->move(s); } + cell *pos(cell *c, const sworddir& sd, bool rev) { + if(WDIM == 2) + return pos2(c, sd.angle + (rev ? sword_angles/2 : 0)); + else { + cell *best = NULL; + ld bdist = HUGE_VAL; + for(int i=0; irelative_matrix(c->move(i)->master, c->master))); + if(dist < bdist) bdist = dist, best = c->move(i); + } + return best; + } + } + eItem orbof(bool rev) { return rev ? itOrbSword2 : itOrbSword; } int orbcount(bool rev) { return items[orbof(rev)]; } cell *pos(int id, bool rev) { if(!orbcount(rev)) return NULL; - return pos(playerpos(id), angle[id] + (rev ? sword_angles/2 : 0)); + return pos(playerpos(id), dir[id], rev); } bool at(cell *where, bool noplayer) { @@ -2673,19 +2690,29 @@ namespace sword { } // from c1 to c2 - int shift(cell *c1, cell *c2, int angle) { - if(!c1 || !c2) return 0; + sworddir shift(cell *c1, cell *c2, sworddir d) { + if(!c1 || !c2) return d; int s1 = neighborId(c1, c2); int s2 = neighborId(c2, c1); - if(s1 < 0 || s2 < 0) return angle; - if(c1->c.mirror(s1)) - return ((s2*sword_angles/c2->type - angle + s1*sword_angles/c1->type) + sword_angles/2) % sword_angles; - else - return ((s2*sword_angles/c2->type - s1*sword_angles/c1->type) + sword_angles/2 + angle) % sword_angles; + if(s1 < 0 || s2 < 0) return d; + if(WDIM == 2) { + if(c1->c.mirror(s1)) + d.angle = ((s2*sword_angles/c2->type - d.angle + s1*sword_angles/c1->type) + sword_angles/2) % sword_angles; + else + d.angle = ((s2*sword_angles/c2->type - s1*sword_angles/c1->type) + sword_angles/2 + d.angle) % sword_angles; + } + else { + transmatrix T = currentmap->relative_matrix(c1->master, c2->master); + T = gpushxto0(tC0(T)) * T; + d.T = T * d.T; + fixmatrix(d.T); + } + return d; } void shuffle(int i) { - sword::angle[i] = euclid ? S7*hrand(6) : PURE ? 3*hrand(sword_angles/3)+1 : hrand(sword_angles); + dir[i].angle = hrand(sword_angles); + dir[i].T = Id; } void reset() { @@ -3217,7 +3244,7 @@ auto ccm = addHook(clearmemory, 0, [] () { gd->store(prairie::enter); gd->store(prairie::tchoices); gd->store(prairie::beaststogen); - gd->store(sword::angle); + gd->store(sword::dir); gd->store(elec::haveelec); gd->store(elec::havecharge); gd->store(elec::lightningfast); diff --git a/game.cpp b/game.cpp index 0d6116ea..62dff079 100644 --- a/game.cpp +++ b/game.cpp @@ -1464,9 +1464,9 @@ bool monstersnear(cell *c, cell *nocount, eMonster who, cell *pushto, cell *come dynamicval x5(*wcw, c); dynamicval x6(stalemate::nextturn, true); - dynamicval x7(sword::angle[multi::cpid], - who == moPlayer ? sword::shift(comefrom, c, sword::angle[multi::cpid]) : - sword::angle[multi::cpid]); + dynamicval x7(sword::dir[multi::cpid], + who == moPlayer ? sword::shift(comefrom, c, sword::dir[multi::cpid]) : + sword::dir[multi::cpid]); for(int b=0; b<2; b++) { if(who == moPlayer) { @@ -3545,7 +3545,7 @@ void playerMoveEffects(cell *c1, cell *c2) { if(peace::on) items[itOrbSword] = c2->land == laBurial ? 100 : 0; - sword::angle[multi::cpid] = sword::shift(c1, c2, sword::angle[multi::cpid]); + sword::dir[multi::cpid] = sword::shift(c1, c2, sword::dir[multi::cpid]); destroyWeakBranch(c1, c2, moPlayer); @@ -5267,8 +5267,8 @@ void sideAttack(cell *mf, int dir, eMonster who, int bonuskill) { template void do_swords(cell *mf, cell *mt, eMonster who, const T& f) { for(int bb=0; bb<2; bb++) if(who == moPlayer && sword::orbcount(bb)) { - cell *sf = sword::pos(mf, sword::angle[multi::cpid] + (bb?sword::sword_angles/2:0)); - cell *st = sword::pos(mt, sword::shift(mf, mt, sword::angle[multi::cpid]) + (bb?sword::sword_angles/2:0)); + cell *sf = sword::pos(mf, sword::dir[multi::cpid], bb); + cell *st = sword::pos(mt, sword::shift(mf, mt, sword::dir[multi::cpid]), bb); f(st, bb); if(sf != st && !isNeighbor(sf,st)) { // also attack the in-transit cell diff --git a/graph.cpp b/graph.cpp index a202a4e2..33052177 100644 --- a/graph.cpp +++ b/graph.cpp @@ -391,18 +391,22 @@ void drawPlayerEffects(const transmatrix& V, cell *c, bool onplayer) { #endif } - else if(shmup::on && WDIM == 3) { + else if(WDIM == 3) { #if CAP_SHAPES + transmatrix Vsword = + shmup::on ? V * shmup::swordmatrix[multi::cpid] * cspin(2, 0, M_PI/2) + : gmatrix[c] * rgpushxto0(inverse(gmatrix[c]) * tC0(V)) * sword::dir[multi::cpid].T; + if(items[itOrbSword]) - queuepoly(V*shmup::swordmatrix[multi::cpid] * cspin(2, 0, M_PI/2) * cspin(1,2, ticks / 150.), (peace::on ? cgi.shMagicShovel : cgi.shMagicSword), darkena(iinf[itOrbSword].color, 0, 0xC0 + 0x30 * sintick(200))); + queuepoly(Vsword * cspin(1,2, ticks / 150.), (peace::on ? cgi.shMagicShovel : cgi.shMagicSword), darkena(iinf[itOrbSword].color, 0, 0xC0 + 0x30 * sintick(200))); if(items[itOrbSword2]) - queuepoly(V*shmup::swordmatrix[multi::cpid] * cspin(2, 0, -M_PI/2) * cspin(1,2, ticks / 150.), (peace::on ? cgi.shMagicShovel : cgi.shMagicSword), darkena(iinf[itOrbSword2].color, 0, 0xC0 + 0x30 * sintick(200))); + queuepoly(Vsword * pispin * cspin(1,2, ticks / 150.), (peace::on ? cgi.shMagicShovel : cgi.shMagicSword), darkena(iinf[itOrbSword2].color, 0, 0xC0 + 0x30 * sintick(200))); #endif } else { - int& ang = angle[multi::cpid]; + int& ang = sword::dir[multi::cpid].angle; ang %= sword::sword_angles; #if CAP_QUEUE || CAP_SHAPES @@ -415,7 +419,7 @@ void drawPlayerEffects(const transmatrix& V, cell *c, bool onplayer) { if(!euclid) for(int a=0; a 48 && !longer) continue; color_t col = darkena(0xC0C0C0, 0, 0xFF); ld l0 = PURE ? 0.6 * cgi.scalefactor : longer ? 0.36 : 0.4; @@ -6862,6 +6866,13 @@ void drawMarkers() { } #endif + + if(WDIM == 3 && !shmup::on) { + if(items[itOrbSword]) + queuechr(gmatrix[cwt.at] * sword::dir[multi::cpid].T * xpush0(cgi.sword_size), vid.fsize*2, '+', iinf[itOrbSword].color); + if(items[itOrbSword2]) + queuechr(gmatrix[cwt.at] * sword::dir[multi::cpid].T * xpush0(-cgi.sword_size), vid.fsize*2, '+', iinf[itOrbSword2].color); + } } monsterToSummon = moNone; diff --git a/hyper.h b/hyper.h index 49b4acf8..c2225a3b 100644 --- a/hyper.h +++ b/hyper.h @@ -1862,12 +1862,17 @@ namespace tortoise { namespace sword { - extern array angle; + struct sworddir { + int angle; + transmatrix T; + }; + + extern array dir; - cell *pos(cell *c, int s); + cell *pos(cell *c, const sworddir& sd, bool rev); cell *pos(int id); bool at(cell *where, bool noplayer = false); - int shift(cell *c1, cell *c2); + sworddir shift(cell *c1, cell *c2, sworddir); } void killThePlayer(eMonster m, int id, flagtype flags); diff --git a/system.cpp b/system.cpp index 04ca6d2f..1b1a136b 100644 --- a/system.cpp +++ b/system.cpp @@ -210,7 +210,10 @@ void initgame() { } sword::determine_sword_angles(); - for(int i=0; itype + 1) / 2; + for(int i=0; itype + 1) / 2; + sword::dir[i].T = Id; + } #if CAP_DAILY daily::split();