From 35301f0a6811152f18502a57e4c33cc9508bee92 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Sun, 17 Jun 2018 17:51:26 +0200 Subject: [PATCH] movement animations now work in quotient geometries --- blizzard.cpp | 4 +- complex.cpp | 16 +++--- conformal.cpp | 10 ++-- control.cpp | 2 +- floorshapes.cpp | 7 ++- game.cpp | 117 ++++++++++++++++++++------------------ graph.cpp | 91 +++++++++++++++++------------ hyper.h | 19 ++++--- orbs.cpp | 26 +++++---- rogueviz-banachtarski.cpp | 2 +- shmup.cpp | 84 +++++++++++++++++++-------- 11 files changed, 226 insertions(+), 152 deletions(-) diff --git a/blizzard.cpp b/blizzard.cpp index 9d7db125..128ad819 100644 --- a/blizzard.cpp +++ b/blizzard.cpp @@ -6,12 +6,12 @@ namespace hr { double randd() { return (rand() + .5) / (RAND_MAX + 1.); } double cellgfxdist(cell *c, int i) { - if(gp::on) return hdist0(tC0(shmup::calc_relative_matrix(c->mov[i], c))); + if(gp::on) return hdist0(tC0(shmup::calc_relative_matrix(c->mov[i], c, i))); return nonbitrunc ? tessf * gp::scale : (c->type == 6 && (i&1)) ? hexhexdist : crossf; } transmatrix cellrelmatrix(cell *c, int i) { - if(gp::on) return shmup::calc_relative_matrix(c->mov[i], c); + if(gp::on) return shmup::calc_relative_matrix(c->mov[i], c, i); double d = cellgfxdist(c, i); return ddspin(c, i) * xpush(d) * iddspin(c->mov[i], c->spin(i), euclid ? 0 : S42); } diff --git a/complex.cpp b/complex.cpp index a84b6e76..4c700f63 100644 --- a/complex.cpp +++ b/complex.cpp @@ -136,7 +136,7 @@ namespace whirlwind { for(int i=0; iitem) - animateMovement(whirlline[i+1], whirlline[i], LAYER_BOAT); + animateMovement(whirlline[i+1], whirlline[i], LAYER_BOAT, NOHINT); } for(int i=0; iwall == waBoat && wto->wall == waSea && !wto->monst) { wfrom->wall = waSea; wto->wall = waBoat; wto->mondir = neighborId(wto, wfrom); - animateMovement(wfrom, wto, LAYER_BOAT); + animateMovement(wfrom, wto, LAYER_BOAT, NOHINT); } if(wfrom && wto && wfrom->item && !wto->item && wfrom->wall != waBoat) { @@ -1206,7 +1206,7 @@ namespace mirror { continue; } c->monst = moMimic; - moveMonster(c2, c); + moveMonster(c2, c, m.second.spin); c2->monst = moNone; empathyMove(c, c2, neighborId(c2, c)); m.second = cw2; @@ -1639,7 +1639,7 @@ namespace hive { // c->monst = moDeadBug, deadbug.push_back(c); } else { - moveMonster(c2, c); + moveMonster(c2, c, d); // pheromones! if(c->land == laHive && c->landparam < 90) c->landparam += 5; if(c2->land == laHive && c2->landparam < 90) c2->landparam += 5; @@ -2297,7 +2297,7 @@ namespace dragon { mountmove(c, c->mondir, true, c2); c->monst = c2->monst; c->hitpoints = c2->hitpoints; - animateMovement(c2, c, LAYER_BIG); + animateMovement(c2, c, LAYER_BIG, c->spin(c->mondir)); c->stuntime = 2; if(c2->mondir == NODIR) { c->mondir = NODIR; c2->monst = moNone; return; } c = c2; @@ -2417,7 +2417,7 @@ namespace dragon { cmt->monst = cft->monst; cft->monst = moNone; mountmove(cmt, cmt->mondir, true, cft); - animateMovement(cft, cmt, LAYER_BIG); + animateMovement(cft, cmt, LAYER_BIG, allcells[i]->mondir); } while(c->mondir != NODIR) { c = c->mov[c->mondir]; @@ -2656,7 +2656,7 @@ namespace kraken { noconflict = false; */ /* if(noconflict) */ { // found = true; - indAnimateMovement(acells[i].first, acells[i].second, LAYER_BIG); + indAnimateMovement(acells[i].first, acells[i].second, LAYER_BIG, NOHINT); acells[i] = acells[size(acells)-1]; acells.resize(size(acells)-1); i--; @@ -2872,7 +2872,7 @@ namespace prairie { } if(!cn->monst && !isPlayerOn(cn) && passable_for(cp->monst, cn, cp, P_DEADLY)) - moveMonster(cn, cp); + moveMonster(cn, cp, NODIR); else { playSound(NULL, "hit-axe"+pick123()); beastcrash(cn, cp); diff --git a/conformal.cpp b/conformal.cpp index 0c081155..fe481cc7 100644 --- a/conformal.cpp +++ b/conformal.cpp @@ -337,10 +337,10 @@ namespace conformal { // virtualRebase(v[j], false); - hyperpoint prev = shmup::calc_relative_matrix(v[j-1]->base, v[j]->base) * + hyperpoint prev = shmup::calc_relative_matrix(v[j-1]->base, v[j]->base, NOHINT) * v[j-1]->at * C0; - hyperpoint next = shmup::calc_relative_matrix(v[j+1]->base, v[j]->base) * + hyperpoint next = shmup::calc_relative_matrix(v[j+1]->base, v[j]->base, NOHINT) * v[j+1]->at * C0; hyperpoint hmid = mid(prev, next); @@ -352,7 +352,7 @@ namespace conformal { } } - hyperpoint next0 = shmup::calc_relative_matrix(v[1]->base, v[0]->base) * v[1]->at * C0; + hyperpoint next0 = shmup::calc_relative_matrix(v[1]->base, v[0]->base, NOHINT) * v[1]->at * C0; v[0]->at = v[0]->at * rspintox(inverse(v[0]->at) * next0); llv = ticks; @@ -380,7 +380,7 @@ namespace conformal { hyperpoint now = v[ph]->at * C0; - hyperpoint next = shmup::calc_relative_matrix(v[ph+1]->base, v[ph]->base) * + hyperpoint next = shmup::calc_relative_matrix(v[ph+1]->base, v[ph]->base, NOHINT) * v[ph+1]->at * C0; View = spin(M_PI/180 * rotation) * xpush(-(phase-ph) * hdist(now, next)) * View; @@ -411,7 +411,7 @@ namespace conformal { for(int j=0; jat) * - shmup::calc_relative_matrix(v[j+1]->base, v[j]->base) * + shmup::calc_relative_matrix(v[j+1]->base, v[j]->base, NOHINT) * v[j+1]->at * C0; hyperpoint nextscr; diff --git a/control.cpp b/control.cpp index d0bf4a3d..ef3c1240 100644 --- a/control.cpp +++ b/control.cpp @@ -110,7 +110,7 @@ void calcMousedest() { ld dists[MAX_EDGE]; for(int i=0; itype; i++) - dists[i] = intval(mouseh, tC0(shmup::ggmatrix(cwt.c->mov[i]))); + dists[i] = intval(mouseh, tC0(confusingGeometry() ? shmup::ggmatrix(cwt.c) * shmup::calc_relative_matrix(cwt.c->mov[i], cwt.c, i) : shmup::ggmatrix(cwt.c->mov[i]))); /* printf("curcell = %Lf\n", mousedist); for(int i=0; itype; i++) diff --git a/floorshapes.cpp b/floorshapes.cpp index 3c905286..2d795d4b 100644 --- a/floorshapes.cpp +++ b/floorshapes.cpp @@ -303,7 +303,7 @@ namespace gp { hyperpoint nearcorner(cell *c, local_info& li, int i) { cellwalker cw(c, i); cw += wstep; - transmatrix cwm = shmup::calc_relative_matrix(cw.c, c); + transmatrix cwm = shmup::calc_relative_matrix(cw.c, c, i); if(elliptic && cwm[2][2] < 0) cwm = centralsym * cwm; return cwm * C0; } @@ -311,7 +311,7 @@ namespace gp { hyperpoint hypercorner(cell *c, local_info& li, int i) { cellwalker cw(c, i); cw += wstep; - transmatrix cwm = shmup::calc_relative_matrix(cw.c, c); + transmatrix cwm = shmup::calc_relative_matrix(cw.c, c, i); if(elliptic && cwm[2][2] < 0) cwm = centralsym * cwm; auto li1 = get_local_info(cw.c); return cwm * get_corner_position(li1, (cw+2).spin); @@ -358,8 +358,9 @@ namespace gp { cellwalker cw(c0, c); cw += d+sidir+siid+1; + int hint = cw.spin; cw += wstep; - transmatrix cwm = shmup::calc_relative_matrix(cw.c, c0); + transmatrix cwm = shmup::calc_relative_matrix(cw.c, c0, hint); hyperpoint nfar = cwm*C0; auto li1 = get_local_info(cw.c); hyperpoint nlfar = cwm * get_corner_position(li1, (cw+2).spin); diff --git a/game.cpp b/game.cpp index 235d7fd2..7dcf91bc 100644 --- a/game.cpp +++ b/game.cpp @@ -734,18 +734,18 @@ bool canPushStatueOn(cell *c) { !isWorm(c->monst) && !isReptile(c->wall) && !peace::on; } -void moveBoat(cell *to, cell *from) { +void moveBoat(cell *to, cell *from, int direction_hint) { eWall x = to->wall; to->wall = from->wall; from->wall = x; to->mondir = neighborId(to, from); moveItem(from, to, false); - animateMovement(from, to, LAYER_BOAT); + animateMovement(from, to, LAYER_BOAT, direction_hint); } -void moveBoatIfUsingOne(cell *to, cell *from) { - if(from->wall == waBoat && isWatery(to)) moveBoat(to, from); +void moveBoatIfUsingOne(cell *to, cell *from, int direction_hint) { + if(from->wall == waBoat && isWatery(to)) moveBoat(to, from, direction_hint); else if(from->wall == waBoat && boatGoesThrough(to) && markEmpathy(itOrbWater)) { placeWater(to, from); - moveBoat(to, from); + moveBoat(to, from, direction_hint); } } @@ -1881,7 +1881,7 @@ bool attackJustStuns(cell *c2, flagtype f) { return isStunnable(c2->monst) && c2->hitpoints > 1; } -void moveEffect(cell *ct, cell *cf, eMonster m); +void moveEffect(cell *ct, cell *cf, eMonster m, int direction_hint); void flameHalfvine(cell *c, int val) { if(itemBurns(c->item)) { @@ -2087,7 +2087,7 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) { } if(m == moVineBeast) petrify(c, waVinePlant, m), pcount = 0; - if(isBird(m)) moveEffect(c, c, moDeadBird); + if(isBird(m)) moveEffect(c, c, moDeadBird, -1); if(m == moBomberbird || m == moTameBomberbird) { pcount = 0; playSound(c, "die-bomberbird"); @@ -2446,8 +2446,8 @@ bool attackMonster(cell *c, flagtype flags, eMonster killer) { return ntk > tk; } -void pushMonster(cell *ct, cell *cf) { - moveMonster(ct, cf); +void pushMonster(cell *ct, cell *cf, int direction_hint) { + moveMonster(ct, cf, direction_hint); } bool destroyHalfvine(cell *c, eWall newwall, int tval) { @@ -3242,7 +3242,7 @@ void activateArrowTrap(cell *c) { // this is called from moveMonster, or separately from moveIvy/moveWorm, // or when a dead bird falls (then m == moDeadBird) -void moveEffect(cell *ct, cell *cf, eMonster m) { +void moveEffect(cell *ct, cell *cf, eMonster m, int direction_hint) { if(cf) destroyWeakBranch(cf, ct, m); @@ -3273,7 +3273,7 @@ void moveEffect(cell *ct, cell *cf, eMonster m) { if(cf && ct->item == itBabyTortoise && !cf->item) { cf->item = itBabyTortoise; ct->item = itNone; - animateMovement(ct, cf, LAYER_BOAT); + animateMovement(ct, cf, LAYER_BOAT, direction_hint); tortoise::babymap[cf] = tortoise::babymap[ct]; tortoise::babymap.erase(ct); } @@ -3407,20 +3407,20 @@ void makeTrollFootprints(cell *c) { c->landparam = turncount + 100; } -void moveMonster(cell *ct, cell *cf) { +void moveMonster(cell *ct, cell *cf, int direction_hint) { eMonster m = cf->monst; bool fri = isFriendly(cf); if(isDragon(m)) { printf("called for Dragon\n"); return; } - if(m != moMimic) animateMovement(cf, ct, LAYER_SMALL); + if(m != moMimic) animateMovement(cf, ct, LAYER_SMALL, direction_hint); // the following line is necessary because otherwise plates disappear only inside the sight range if(cellUnstable(cf) && !ignoresPlates(m)) { fallingFloorAnimation(cf); cf->wall = waChasm; } - moveEffect(ct, cf, m); + moveEffect(ct, cf, m, direction_hint); if(ct->wall == waCamelotMoat && (m == moShark || m == moCShark || m == moGreaterShark)) achievement_gain("MOATSHARK"); @@ -3460,10 +3460,10 @@ void moveMonster(cell *ct, cell *cf) { if(ct->wall == waBigStatue) { ct->wall = cf->wall; cf->wall = waBigStatue; - animateMovement(ct, cf, LAYER_BOAT); + animateMovement(ct, cf, LAYER_BOAT, revhint(cf, direction_hint)); } - moveBoatIfUsingOne(ct, cf); + moveBoatIfUsingOne(ct, cf, revhint(cf, direction_hint)); } if(isTroll(m)) { makeTrollFootprints(ct); makeTrollFootprints(cf); } @@ -3894,7 +3894,7 @@ int pickDownDirection(cell *c, flagtype mf) { } template -cell *determinePush(cellwalker who, cell *c2, int subdir, const T& valid) { +cell *determinePush(cellwalker who, cell *c2, int subdir, const T& valid, int& pushdir) { if(subdir != 1 && subdir != -1) { subdir = 1; static bool first = true; @@ -3910,6 +3910,7 @@ cell *determinePush(cellwalker who, cell *c2, int subdir, const T& valid) { if(valid(push.c)) return push.c; if(c2->type&1) { push = push + wstep - subdir + wstep; + pushdir = (push+wstep).spin; if(valid(push.c)) return push.c; } if(gravityLevel(push.c) < gravityLevel(c2)) { @@ -3920,6 +3921,7 @@ cell *determinePush(cellwalker who, cell *c2, int subdir, const T& valid) { if(gravityLevel(push.c) < gravityLevel(c2)) { push = push + wstep + 1 + wstep; } + pushdir = (push+wstep).spin; if(valid(push.c)) return push.c; } return c2; @@ -3939,9 +3941,10 @@ void beastAttack(cell *c, bool player) { if(c2->monst && c2->stuntime) { cellwalker bull (c, d); int subdir = determinizeBullPush(bull); - cell *c3 = determinePush(bull, c2, subdir, [c2] (cell *c) { return passable(c, c2, P_BLOW); }); + int pushdir; + cell *c3 = determinePush(bull, c2, subdir, [c2] (cell *c) { return passable(c, c2, P_BLOW); }, pushdir); if(c3 && c3 != c2) - pushMonster(c3, c2); + pushMonster(c3, c2, pushdir); } } if(c2->wall == waThumperOff) { @@ -3951,7 +3954,8 @@ void beastAttack(cell *c, bool player) { if(c2->wall == waThumperOn) { cellwalker bull (c, d); int subdir = determinizeBullPush(bull); - cell *c3 = determinePush(bull, c2, subdir, [c2] (cell *c) { return canPushThumperOn(c, c2, c); }); + int pushdir; + cell *c3 = determinePush(bull, c2, subdir, [c2] (cell *c) { return canPushThumperOn(c, c2, c); }, pushdir); if(c3 && c3 != c2) pushThumper(c2, c3); } @@ -4002,13 +4006,13 @@ cell *moveNormal(cell *c, flagtype mf) { } else if(m2) { attackMonster(c2, AF_NORMAL | AF_MSG, m); - animateAttack(c, c2, LAYER_SMALL); + animateAttack(c, c2, LAYER_SMALL, d); if(m == moFlailer && m2 == moIllusion) attackMonster(c, 0, m2); return c2; } - moveMonster(c2, c); + moveMonster(c2, c, d); if(m == moRagingBull) beastAttack(c2, false); return c2; } @@ -4036,7 +4040,7 @@ cell *moveNormal(cell *c, flagtype mf) { if(!attacking) for(int i=0; imov[posdir[i]]; if(!c->monst) c->monst = m; - moveMonster(c2, c); + moveMonster(c2, c, posdir[i]); if(m == moRagingBull) beastAttack(c2, false); } return c->mov[d]; @@ -4177,7 +4181,7 @@ void mountmove(cell *c, int spin, bool fp, int id) { void mountmove(cell *c, int spin, bool fp, cell *ppos) { for(int i=0; imonst != moTentacleGhost && cmt->monst != moTentacleGhost) mountmove(cmt, cft->spn(cft->mondir), false, cft); - animateMovement(cft, cmt, LAYER_BIG); + animateMovement(cft, cmt, LAYER_BIG, cft->mondir); } c->monst = moNone; if(c->mondir != NODIR) c->mov[c->mondir]->monst = moTentacleEscaping; @@ -4283,9 +4287,9 @@ void moveWorm(cell *c) { for(int j=0; jtype; j++) if(c->mov[j] == goal) { goal->monst = eMonster(moWormwait + id); - moveEffect(goal, NULL, eMonster(moWormwait + id)); + moveEffect(goal, NULL, eMonster(moWormwait + id), NOHINT); - animateMovement(c, goal, LAYER_BIG); + animateMovement(c, goal, LAYER_BIG, dir); c->monst = eMonster(moWormtail + id); goal->mondir = c->spn(j); @@ -4301,7 +4305,7 @@ void moveWorm(cell *c) { c3 = c2, c2 = c3->mov[c2->mondir]; if(c3->monst != moTentacleGhost && c2->monst != moTentacleGhost) mountmove(c3, c3->mondir, true, c2); - animateMovement(c2, c3, LAYER_BIG); + animateMovement(c2, c3, LAYER_BIG, c2->spin(c2->mondir)); } } @@ -4314,7 +4318,7 @@ void moveWorm(cell *c) { } c3 = c2, c2 = c3->mov[c2->mondir]; mountmove(c3, c3->mondir, true, c2); - animateMovement(c2, c3, LAYER_BIG); + animateMovement(c2, c3, LAYER_BIG, revhint(c2, c2->mondir)); } } @@ -4415,9 +4419,9 @@ void moveivy() { } if(mto && mto->cpdist) { - animateMovement(mto->mov[sp], mto, LAYER_BIG); + animateMovement(mto->mov[sp], mto, LAYER_BIG, mto->spin(sp)); mto->monst = moIvyWait, mto->mondir = sp; - moveEffect(mto, NULL, moIvyWait); + moveEffect(mto, NULL, moIvyWait, NOHINT); // if this is the only branch, we want to move the head immediately to mto instead if(mto->mov[mto->mondir]->monst == moIvyHead) { mto->monst = moIvyHead; co->monst = moIvyBranch; @@ -4527,7 +4531,7 @@ void groupmove2(cell *c, cell *from, int d, eMonster movtype, flagtype mf) { if(!(mf & MF_NOATTACKS)) for(int j=0; jtype; j++) if(c->mov[j] && canAttack(c, c->monst, c->mov[j], c->mov[j]->monst, af)) { attackMonster(c->mov[j], AF_NORMAL | AF_GETPLAYER | AF_MSG, c->monst); - animateAttack(c, c->mov[j], LAYER_SMALL); + animateAttack(c, c->mov[j], LAYER_SMALL, j); c->aitmp = sval; // XLATC eagle return; @@ -4540,7 +4544,7 @@ void groupmove2(cell *c, cell *from, int d, eMonster movtype, flagtype mf) { return; } - moveMonster(from, c); + moveMonster(from, c, revhint(from, d)); from->aitmp = sval; } c->aitmp = sval; @@ -4612,12 +4616,12 @@ vector hexdfs; // note: move from 'c' to 'from'! void moveHexSnake(cell *from, cell *c, int d, bool mounted) { if(from->wall == waBoat) from->wall = waSea; - moveEffect(from, c, c->monst); + moveEffect(from, c, c->monst, revhint(from, d)); from->monst = c->monst; from->mondir = d; from->hitpoints = c->hitpoints; c->monst = moHexSnakeTail; preventbarriers(from); - animateMovement(c, from, LAYER_BIG); + animateMovement(c, from, LAYER_BIG, revhint(from, d)); mountmove(from, from->mondir, true, c); cell *c2 = c, *c3=c2; @@ -4625,7 +4629,7 @@ void moveHexSnake(cell *from, cell *c, int d, bool mounted) { if(a == ROCKSNAKELENGTH) { c2->monst = moNone, c3->mondir = NODIR; break; } if(c2->mondir == NODIR) break; mountmove(c2, c2->mondir, true, c2->mov[c2->mondir]); - animateMovement(c2->mov[c2->mondir], c2, LAYER_BIG); + animateMovement(c2->mov[c2->mondir], c2, LAYER_BIG, revhint(c2, c2->mondir)); c3 = c2, c2 = c3->mov[c2->mondir]; } else break; @@ -4787,7 +4791,7 @@ void movemutant() { c2->monst = moMutant; c2->mondir = c->spn(j); c2->stuntime = mutantphase; - animateMovement(c, c2, LAYER_BIG); + animateMovement(c, c2, LAYER_BIG, j); } } } @@ -4823,7 +4827,7 @@ void moveshadow() { cell* where = shpos[p][cshpos]; if(where && where->monst == moNone && where->cpdist && where->land == laGraveyard && !sword::at(where)) { - if(shfrom) animateMovement(shfrom, where, LAYER_SMALL); + if(shfrom) animateMovement(shfrom, where, LAYER_SMALL, NOHINT); where->monst = moShadow; where->hitpoints = p; where->stuntime = 0; @@ -4881,7 +4885,7 @@ void moveghosts() { addMessage(XLAT("%The1 scares %the2 a bit!", c->monst, c2->monst)); c2->stuntime = 1; } - else moveMonster(c2, c); + else moveMonster(c2, c, d); } nextghost: ; @@ -5249,7 +5253,7 @@ void movegolems(flagtype flags) { else if((flags & AF_CRUSH) && !canAttack(c, m, c2, c2->monst, flags ^ AF_CRUSH ^ AF_MUSTKILL)) markOrb(itOrbEmpathy), markOrb(itOrbSlaying); attackMonster(c2, flags | AF_MSG, m); - animateAttack(c, c2, LAYER_SMALL); + animateAttack(c, c2, LAYER_SMALL, dir); produceGhost(c2, m2, m); sideAttack(c, dir, m, 0); if(revenge) c->monst = m = moPrincessArmed; @@ -5261,9 +5265,9 @@ void movegolems(flagtype flags) { else { passable_for(m, c2, c, P_DEADLY); DEBT("move"); - moveMonster(c2, c); + moveMonster(c2, c, dir); if(m != moTameBomberbird && m != moFriendlyGhost) - moveBoatIfUsingOne(c2, c); + moveBoatIfUsingOne(c2, c, dir); if(c2->monst == m) { if(m == moGolem) c2->monst = moGolemMoved; @@ -7396,7 +7400,8 @@ bool movepcto(int d, int subdir, bool checkonly) { } if(c2->wall == waThumperOn && !c2->monst && !nonAdjacentPlayer(c2, cwt.c)) { - cell *c3 = determinePush(cwt, c2, subdir, [c2] (cell *c) { return canPushThumperOn(c, c2, cwt.c); }); + int pushdir; + cell *c3 = determinePush(cwt, c2, subdir, [c2] (cell *c) { return canPushThumperOn(c, c2, cwt.c); }, pushdir); if(c3 == c2) { if(checkonly) return false; addMessage(XLAT("No room to push %the1.", c2->wall)); @@ -7446,7 +7451,7 @@ bool movepcto(int d, int subdir, bool checkonly) { } if(checkonly) return true; - moveBoat(c2, cwt.c); + moveBoat(c2, cwt.c, d); boatmove = true; goto boatjump; } @@ -7462,8 +7467,8 @@ bool movepcto(int d, int subdir, bool checkonly) { if(checkonly) return true; if(c2->item && !cwt.c->item) moveItem(c2, cwt.c, false), boatmove = true; placeWater(c2, cwt.c); - moveBoat(c2, cwt.c); - c2->mondir = neighborId(c2, cwt.c); + moveBoat(c2, cwt.c, d); + c2->mondir = revhint(cwt.c, d); if(c2->item) boatmove = !boatmove; goto boatjump; } @@ -7495,7 +7500,7 @@ bool movepcto(int d, int subdir, bool checkonly) { if(checkonly) { c2->wall = save_c2; cwt.c->wall = save_cw; return true; } addMessage(XLAT("You push %the1 behind you!", waBigStatue)); - animateMovement(c2, cwt.c, LAYER_BOAT); + animateMovement(c2, cwt.c, LAYER_BOAT, cwt.c->spin(d)); goto statuejump; } @@ -7522,7 +7527,7 @@ bool movepcto(int d, int subdir, bool checkonly) { playSound(c2, "hit-axe" + pick123()); c2->wall = waNone; sideAttack(cwt.c, d, moPlayer, 0); - animateAttack(cwt.c, c2, LAYER_SMALL); + animateAttack(cwt.c, c2, LAYER_SMALL, d); } else if(c2->wall == waBigTree) { drawParticles(c2, winf[c2->wall].color, 8); @@ -7530,13 +7535,13 @@ bool movepcto(int d, int subdir, bool checkonly) { playSound(c2, "hit-axe" + pick123()); c2->wall = waSmallTree; sideAttack(cwt.c, d, moPlayer, 0); - animateAttack(cwt.c, c2, LAYER_SMALL); + animateAttack(cwt.c, c2, LAYER_SMALL, d); } else { if(!peace::on) { addMessage(XLAT("You swing your sword at the mirror.")); sideAttack(cwt.c, d, moPlayer, 0); - animateAttack(cwt.c, c2, LAYER_SMALL); + animateAttack(cwt.c, c2, LAYER_SMALL, d); } } if(survivalist && isHaunted(c2->land)) @@ -7601,9 +7606,10 @@ bool movepcto(int d, int subdir, bool checkonly) { // pushto=c2 means that the monster is not killed and thus // still counts for lightning in monstersnear cell *pushto = NULL; + int pushdir = 0; if(isStunnable(c2->monst) && c2->hitpoints > 1) { if(monsterPushable(c2)) - pushto = determinePush(cwt, c2, subdir, [c2] (cell *c) { return passable(c, c2, P_BLOW); }); + pushto = determinePush(cwt, c2, subdir, [c2] (cell *c) { return passable(c, c2, P_BLOW); }, pushdir); else pushto = c2; } @@ -7661,8 +7667,8 @@ bool movepcto(int d, int subdir, bool checkonly) { // salamanders are stunned for longer time when pushed into a wall if(c2->monst == moSalamander && (pushto == c2 || !pushto)) c2->stuntime = 10; if(!c2->monst) produceGhost(c2, m, moPlayer); - if(pushto && pushto != c2) pushMonster(pushto, c2); - animateAttack(cwt.c, c2, LAYER_SMALL); + if(pushto && pushto != c2) pushMonster(pushto, c2, pushdir); + animateAttack(cwt.c, c2, LAYER_SMALL, d); } } @@ -7840,11 +7846,12 @@ bool movepcto(int d, int subdir, bool checkonly) { stabbingAttack(cwt.c, c2, moPlayer); cell *c1 = cwt.c; + int d = cwt.spin; cwt += wstep; if(switchplaces) - animateReplacement(c1, cwt.c, LAYER_SMALL); + animateReplacement(c1, cwt.c, LAYER_SMALL, d, cwt.spin); else - animateMovement(c1, cwt.c, LAYER_SMALL); + animateMovement(c1, cwt.c, LAYER_SMALL, d); mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK | mirror::GO); diff --git a/graph.cpp b/graph.cpp index d77db571..a17d78e0 100644 --- a/graph.cpp +++ b/graph.cpp @@ -2090,7 +2090,7 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) { Vb = Vb * xpush(tentacle_length - cellgfxdist(c, c->mondir)); } else if(gp::on) { - transmatrix T = shmup::calc_relative_matrix(c->mov[c->mondir], c); + transmatrix T = shmup::calc_relative_matrix(c->mov[c->mondir], c, c->mondir); Vb = Vb * T * rspintox(tC0(inverse(T))) * xpush(tentacle_length); } else { @@ -2139,6 +2139,10 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) { Vs = playerV; if(multi::players > 1 ? multi::flipped[i] : flipplayer) Vs = Vs * pispin; } + else { + bool mirr = multi::players > 1 ? multi::player[i].mirrored : cwt.mirrored; + if(mirr) Vs = Vs * Mirror; + } shmup::cpid = i; drawPlayerEffects(Vs, c, true); @@ -2562,7 +2566,7 @@ void drawMovementArrows(cell *c, transmatrix V) { int sd = md.subdir; queuepoly(inverse(Centered) * rgpushxto0(Centered * tC0(V)) * rspintox(Centered*tC0(V)) * spin(-sd * M_PI/S7) * xpush(0.2), shArrow, col); } - else break; + else if(!confusingGeometry()) break; } } } @@ -4963,15 +4967,15 @@ void drawMarkers() { if((vid.axes == 4 || (vid.axes == 1 && !mousing)) && !shmup::on) { if(multi::players == 1) { - forCellAll(c2, cwt.c) IG(c2) drawMovementArrows(c2, Gm(c2)); + forCellIdAll(c2, d, cwt.c) IG(c2) drawMovementArrows(c2, confusingGeometry() ? Gm(cwt.c) * shmup::calc_relative_matrix(c2, cwt.c, d) : Gm(c2)); } else if(multi::players > 1) for(int p=0; p ttm(cwtV, multi::whereis[p]); dynamicval tcw(cwt, multi::player[p]); - drawMovementArrows(c2, Gm(c2)); + drawMovementArrows(c2, confusingGeometry() ? Gm(cwt.c) * shmup::calc_relative_matrix(c2, cwt.c, d) : Gm(c2)); } } } @@ -5740,51 +5744,68 @@ void resetGeometry() { map animations[ANIMLAYERS]; unordered_map gmatrix, gmatrix0; -void animateMovement(cell *src, cell *tgt, int layer) { +int revhint(cell *c, int hint) { + if(hint >= 0 && hint < c->type) return c->spin(hint); + else return hint; + } + +bool compute_relamatrix(cell *src, cell *tgt, int direction_hint, transmatrix& T) { + if(confusingGeometry()) { + T = shmup::calc_relative_matrix(src, tgt, revhint(src, direction_hint)); + } + else { + if(gmatrix.count(src) && gmatrix.count(tgt)) + T = inverse(gmatrix[tgt]) * gmatrix[src]; + else + return false; + } + return true; + } + + +void animateMovement(cell *src, cell *tgt, int layer, int direction_hint) { if(vid.mspeed >= 5) return; // no animations! - if(confusingGeometry()) return; - if(gmatrix.count(src) && gmatrix.count(tgt)) { - animation& a = animations[layer][tgt]; - if(animations[layer].count(src)) { - a = animations[layer][src]; - a.wherenow = inverse(gmatrix[tgt]) * gmatrix[src] * a.wherenow; - animations[layer].erase(src); - a.attacking = 0; - } - else { - a.ltick = ticks; - a.wherenow = inverse(gmatrix[tgt]) * gmatrix[src]; - a.footphase = 0; - } + transmatrix T; + if(!compute_relamatrix(src, tgt, direction_hint, T)) return; + animation& a = animations[layer][tgt]; + if(animations[layer].count(src)) { + a = animations[layer][src]; + a.wherenow = T * a.wherenow; + animations[layer].erase(src); + a.attacking = 0; + } + else { + a.ltick = ticks; + a.wherenow = T; + a.footphase = 0; } } -void animateAttack(cell *src, cell *tgt, int layer) { +void animateAttack(cell *src, cell *tgt, int layer, int direction_hint) { if(vid.mspeed >= 5) return; // no animations! - if(gmatrix.count(src) && gmatrix.count(tgt)) { - bool newanim = !animations[layer].count(src); - animation& a = animations[layer][src]; - a.attacking = 1; - a.attackat = rspintox(tC0(inverse(gmatrix[src]) * gmatrix[tgt])) * xpush(hdist(gmatrix[src]*C0, gmatrix[tgt]*C0) / 3); - if(newanim) a.wherenow = Id, a.ltick = ticks, a.footphase = 0; - } + transmatrix T; + if(!compute_relamatrix(src, tgt, direction_hint, T)) return; + bool newanim = !animations[layer].count(src); + animation& a = animations[layer][src]; + a.attacking = 1; + a.attackat = rspintox(tC0(inverse(T))) * xpush(hdist0(T*C0) / 3); + if(newanim) a.wherenow = Id, a.ltick = ticks, a.footphase = 0; } vector > animstack; -void indAnimateMovement(cell *src, cell *tgt, int layer) { +void indAnimateMovement(cell *src, cell *tgt, int layer, int direction_hint) { if(vid.mspeed >= 5) return; // no animations! - if(confusingGeometry()) return; if(animations[layer].count(tgt)) { animation res = animations[layer][tgt]; animations[layer].erase(tgt); - animateMovement(src, tgt, layer); + animateMovement(src, tgt, layer, direction_hint); if(animations[layer].count(tgt)) animstack.push_back(make_pair(tgt, animations[layer][tgt])); animations[layer][tgt] = res; } else { - animateMovement(src, tgt, layer); + animateMovement(src, tgt, layer, direction_hint); if(animations[layer].count(tgt)) { animstack.push_back(make_pair(tgt, animations[layer][tgt])); animations[layer].erase(tgt); @@ -5798,13 +5819,13 @@ void commitAnimations(int layer) { animstack.clear(); } -void animateReplacement(cell *a, cell *b, int layer) { +void animateReplacement(cell *a, cell *b, int layer, int direction_hinta, int direction_hintb) { if(vid.mspeed >= 5) return; // no animations! static cell c1; gmatrix[&c1] = gmatrix[b]; if(animations[layer].count(b)) animations[layer][&c1] = animations[layer][b]; - animateMovement(a, b, layer); - animateMovement(&c1, a, layer); + animateMovement(a, b, layer, direction_hinta); + animateMovement(&c1, a, layer, direction_hintb); } void drawBug(const cellwalker& cw, int col) { diff --git a/hyper.h b/hyper.h index 9aabd739..6253fa55 100644 --- a/hyper.h +++ b/hyper.h @@ -478,7 +478,7 @@ bool movepcto(int d, int subdir = 1, bool checkonly = false); void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill = 0); bool earthMove(cell *from, int dir); void messageKill(eMonster killer, eMonster victim); -void moveMonster(cell *ct, cell *cf); +void moveMonster(cell *ct, cell *cf, int direction_hint); int palaceHP(); void placeLocalOrbs(cell *c); int elementalKills(); @@ -652,7 +652,7 @@ namespace shmup { void virtualRebase(cell*& base, transmatrix& at, bool tohex); void virtualRebase(shmup::monster *m, bool tohex); - transmatrix calc_relative_matrix(cell *c, cell *c1); + transmatrix calc_relative_matrix(cell *c, cell *c1, int direction_hint); void fixStorage(); void addShmupHelp(string& out); void activateArrow(cell *c); @@ -663,6 +663,8 @@ namespace shmup { void popmonsters(); } +static const int NOHINT = -1; + // graph void showMissionScreen(); @@ -1550,16 +1552,16 @@ struct animation { extern map animations[ANIMLAYERS]; extern unordered_map gmatrix, gmatrix0; -void animateAttack(cell *src, cell *tgt, int layer); +void animateAttack(cell *src, cell *tgt, int layer, int direction_hint); -void animateMovement(cell *src, cell *tgt, int layer); +void animateMovement(cell *src, cell *tgt, int layer, int direction_hint); // for animations which might use the same locations, // such as replacements or multi-tile monsters -void indAnimateMovement(cell *src, cell *tgt, int layer); +void indAnimateMovement(cell *src, cell *tgt, int layer, int direction_hint); void commitAnimations(int layer); -void animateReplacement(cell *a, cell *b, int layer); +void animateReplacement(cell *a, cell *b, int layer, int direction_hinta, int direction_hintb); void fallingFloorAnimation(cell *c, eWall w = waNone, eMonster m = moNone); void fallingMonsterAnimation(cell *c, eMonster m, int id = multi::cpid); @@ -2778,7 +2780,6 @@ namespace texture { void showMenu(); void drawPixel(cell *c, hyperpoint h, int col); - extern cell *where; // compute 'c' automatically, based on the hint in 'where' void drawPixel(hyperpoint h, int col); @@ -3502,4 +3503,8 @@ void gdpush(int t); extern int fontscale; +bool confusingGeometry(); + +int revhint(cell *c, int hint); + } \ No newline at end of file diff --git a/orbs.cpp b/orbs.cpp index c95eb9df..727dc630 100644 --- a/orbs.cpp +++ b/orbs.cpp @@ -577,7 +577,7 @@ void jumpTo(cell *dest, eItem byWhat, int bonuskill, eMonster dashmon) { killFriendlyIvy(); cell *c1 = cwt.c; - animateMovement(cwt.c, dest, LAYER_SMALL); + animateMovement(cwt.c, dest, LAYER_SMALL, NOHINT); cwt.c = dest; forCellIdEx(c2, i, dest) if(c2->cpdist < dest->cpdist) { cwt.spin = i; @@ -619,13 +619,13 @@ void jumpTo(cell *dest, eItem byWhat, int bonuskill, eMonster dashmon) { monstersTurn(); } -void growIvyTo(cell *dest, cell *src) { +void growIvyTo(cell *dest, cell *src, int direction_hint) { if(dest->monst) attackMonster(dest, AF_NORMAL | AF_MSG, moFriendlyIvy); else { dest->monst = moFriendlyIvy; dest->mondir = neighborId(dest, src); - moveEffect(dest, src, moFriendlyIvy); + moveEffect(dest, src, moFriendlyIvy, direction_hint); empathyMove(src, dest, neighborId(src, dest)); } createNoise(1); @@ -797,7 +797,7 @@ void summonAt(cell *dest) { if(dest->monst == moTortoise) tortoise::emap[dest] = dest; addMessage(XLAT("You summon %the1!", dest->monst)); - moveEffect(dest, dest, dest->monst); + moveEffect(dest, dest, dest->monst, -1); if(dest->wall == waClosePlate || dest->wall == waOpenPlate) toggleGates(dest, dest->wall); @@ -865,7 +865,7 @@ void gun_attack(cell *dest) { void checkStunKill(cell *dest) { if(isBird(dest->monst)) { - moveEffect(dest, dest, moDeadBird); + moveEffect(dest, dest, moDeadBird, NOHINT); doesFall(dest); if(isWatery(dest) || dest->wall == waChasm || isFire(dest)) { addMessage(XLAT("%The1 falls!", dest->monst)); @@ -925,10 +925,10 @@ void placeIllusion(cell *c) { checkmoveO(); } -void blowoff(cell *cf, cell *ct) { +void blowoff(cell *cf, cell *ct, int direction_hint) { playSound(ct, "orb-ranged"); addMessage(XLAT("You blow %the1 away!", cf->monst)); - pushMonster(ct, cf); + pushMonster(ct, cf, direction_hint); if(cf->item == itBabyTortoise && !ct->item) moveItem(cf, ct, true); items[itOrbAir]--; @@ -1024,9 +1024,10 @@ eItem targetRangedOrb(cell *c, orbAction a) { for(; dtype; d++) if(c->mov[d] && c->mov[d]->cpdist < c->cpdist) break; if(dtype) for(int e=d; etype; e++) { nowhereToBlow = true; - cell *c2 = c->mov[e % c->type]; + int di = e % c->type; + cell *c2 = c->mov[di]; if(c2 && c2->cpdist > c->cpdist && passable(c2, c, P_BLOW)) { - if(!isCheck(a)) blowoff(c, c2); + if(!isCheck(a)) blowoff(c, c2, di); return itOrbAir; } } @@ -1035,8 +1036,9 @@ eItem targetRangedOrb(cell *c, orbAction a) { // nature if(items[itOrbNature] && numplayers() == 1 && c->monst != moFriendlyIvy) { cell *sides[8]; + int dirs[8]; int qsides = 0; - forCellCM(cf, c) + forCellIdCM(cf, d, c) if(cf->monst == moFriendlyIvy) { if(c->monst) { @@ -1048,11 +1050,13 @@ eItem targetRangedOrb(cell *c, orbAction a) { if(strictlyAgainstGravity(c, cf, false, MF_IVY)) continue; if(monstersnear(cwt.c, NULL, moPlayer, c, cwt.c)) continue; } + dirs[qsides] = d; sides[qsides++] = cf; } if(qsides > 0) { - if(!isCheck(a)) growIvyTo(c, sides[hrand(qsides)]); + int di = hrand(qsides); + if(!isCheck(a)) growIvyTo(c, sides[di], revhint(c, dirs[di])); return itOrbNature; } } diff --git a/rogueviz-banachtarski.cpp b/rogueviz-banachtarski.cpp index 43d098be..42d574da 100644 --- a/rogueviz-banachtarski.cpp +++ b/rogueviz-banachtarski.cpp @@ -334,7 +334,7 @@ void bantar_frame() { View = Id; - transmatrix tView = actualV(cth(xcw), Id) * shmup::calc_relative_matrix(cwt.c, xcw.c) * inverse(actualV(cth(cwt), Id)); + transmatrix tView = actualV(cth(xcw), Id) * shmup::calc_relative_matrix(cwt.c, xcw.c, NOHINT) * inverse(actualV(cth(cwt), Id)); if(tphase < 2) part = 0; else if(tphase == 2) diff --git a/shmup.cpp b/shmup.cpp index 9cff3783..a6115aec 100644 --- a/shmup.cpp +++ b/shmup.cpp @@ -1624,7 +1624,7 @@ void movePlayer(monster *m, int delta) { m->base->wall = waChasm; else { m->base->wall = waBigStatue; - animateMovement(c2, m->base, LAYER_BOAT); + animateMovement(c2, m->base, LAYER_BOAT, NOHINT); } } else if(m->inBoat && !isWateryOrBoat(c2) && passable(c2, m->base, P_ISPLAYER | P_MIRROR | reflectflag)) { @@ -2728,7 +2728,7 @@ void moveMonster(monster *m, int delta) { m->base->wall = waChasm; else m->base->wall = waBigStatue; - animateMovement(c2, m->base, LAYER_BOAT); + animateMovement(c2, m->base, LAYER_BOAT, NOHINT); } if(passable_for(m->type, c2, m->base, P_CHAIN | P_ONPLAYER | reflectflag) && !isWatery(c2) && m->inBoat) { if(isWatery(m->base)) @@ -3336,7 +3336,7 @@ transmatrix master_relative(cell *c, bool get_inverse) { return T; } } - else if(!nonbitrunc) { + else if(!nonbitrunc && !euclid) { for(int d=0; dmaster->c7->mov[d] == c) return (get_inverse?invhexmove:hexmove)[d]; return Id; @@ -3345,7 +3345,8 @@ transmatrix master_relative(cell *c, bool get_inverse) { return pispin * Id; } -transmatrix calc_relative_matrix(cell *c2, cell *c1) { +// target, source, direction from source to target +transmatrix calc_relative_matrix(cell *c2, cell *c1, int direction_hint) { if(sphere) { if(!gmatrix0.count(c2) || !gmatrix0.count(c1)) { @@ -3358,14 +3359,46 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1) { swap(gmatrix, gmatrix0); gp::draw_li = bak; } - if(gmatrix0.count(c2) && gmatrix0.count(c1)) - return inverse(gmatrix0[c1]) * gmatrix0[c2]; + if(gmatrix0.count(c2) && gmatrix0.count(c1)) { + transmatrix T = inverse(gmatrix0[c1]) * gmatrix0[c2]; + if(elliptic && T[2][2] < 0) + T = centralsym * T; + return T; + } else { printf("error: gmatrix0 not known\n"); return Id; } } + if(torus) { + transmatrix t = Id; + if(whateveri) printf("[%p,%d] ", c2, celldistance(c2, c1)); + int mirrors = 0; + approach: + int d = celldistance(c2, c1); + forCellIdEx(c3, i, c2) { + if(celldistance(c3, c1) < d) { + if(whateveri) printf(" %d [%p,%d]", i, c3, celldistance(c3, c1)); + if(c2->type < 8) + t = eumovedir(i+(euclid6?3:2)) * t; + else if(i&1) + t = eumovedir(2+i/2) * eumovedir(2+(i+1)/2) * t; + else + t = eumovedir(2+i/2) * t; + if(c2->mirror(i)) mirrors++; + c2 = c3; + goto approach; + } + } + if(d != 0) printf("ERROR not reached\n"); + if(mirrors&1) t = Mirror * t * Mirror; + if(whateveri) printf(" => %p\n", c1); + return t; + } + + if(euclid) return inverse(gmatrix0[c1]) * gmatrix0[c2]; + heptagon *h1 = c1->master; transmatrix gm = master_relative(c1, true); heptagon *h2 = c2->master; @@ -3375,20 +3408,26 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1) { //bool hsol = false; //transmatrix sol; while(h1 != h2) { - int confusion = 0; - if(quotient == 1 && gp::on) { - for(int d=0; dmove[d] == h1) confusion++; - if(confusion > 1) { - transmatrix T; - confusion = 0; - for(int d=0; dmove[d] == h1) { - int sp = h2->spin(d); - transmatrix T1 = gm * heptmove[sp] * spin(2*M_PI*d/S7) * where; - if(confusion == 0 || T1[2][2] < T[2][2]) T = T1; - confusion++; + if(quotient == 1) { + transmatrix T; + hyperpoint hint = ddspin(c1, direction_hint) * xpush(1e-2) * C0; + ld bestdist = 1e9; + for(int d=0; dmove[d]) { + int sp = h2->spin(d); + transmatrix S = heptmove[sp] * spin(2*M_PI*d/S7); + if(h2->move[d] == h1) { + transmatrix T1 = gm * S * where; + auto curdist = hdist(tC0(T1), hint); + if(curdist < bestdist) T = T1, bestdist = curdist; + } + for(int e=0; emove[d]->move[e] == h1) { + int sp2 = h2->move[d]->spin(e); + transmatrix T1 = gm * heptmove[sp2] * spin(2*M_PI*e/S7) * S * where; + auto curdist = hdist(tC0(T1), hint); + if(curdist < bestdist) T = T1, bestdist = curdist; } - return T; } + return T; } for(int d=0; dmove[d] == h1) { int sp = h2->spin(d); @@ -3421,17 +3460,14 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1) { transmatrix &ggmatrix(cell *c) { transmatrix& t = gmatrix[c]; if(t[2][2] == 0) { - if(torus) { - forCellIdEx(c2, i, c) - if(celldistance(c2, centerover.c) < celldistance(c, centerover.c)) - t = ggmatrix(c2) * eumovedir(3+i); - } + if(torus && centerover.c) + t = calc_relative_matrix(c, centerover.c, NOHINT); else if(euclid) { if(!centerover.c) centerover = cwt; t = View * eumove(cell_to_vec(c) - cellwalker_to_vec(centerover)); } else - t = actualV(viewctr, cview()) * calc_relative_matrix(c, viewctr.h->c7); + t = actualV(viewctr, cview()) * calc_relative_matrix(c, viewctr.h->c7, NOHINT); } return t; }