1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-06-15 18:00:04 +00:00

movement animations now work in quotient geometries

This commit is contained in:
Zeno Rogue 2018-06-17 17:51:26 +02:00
parent 95a2f617cf
commit 35301f0a68
11 changed files with 226 additions and 152 deletions

View File

@ -6,12 +6,12 @@ namespace hr {
double randd() { return (rand() + .5) / (RAND_MAX + 1.); } double randd() { return (rand() + .5) / (RAND_MAX + 1.); }
double cellgfxdist(cell *c, int i) { 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; return nonbitrunc ? tessf * gp::scale : (c->type == 6 && (i&1)) ? hexhexdist : crossf;
} }
transmatrix cellrelmatrix(cell *c, int i) { 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); double d = cellgfxdist(c, i);
return ddspin(c, i) * xpush(d) * iddspin(c->mov[i], c->spin(i), euclid ? 0 : S42); return ddspin(c, i) * xpush(d) * iddspin(c->mov[i], c->spin(i), euclid ? 0 : S42);
} }

View File

@ -136,7 +136,7 @@ namespace whirlwind {
for(int i=0; i<z-1; i++) { for(int i=0; i<z-1; i++) {
moveItem(whirlline[i], whirlline[i+1], true); moveItem(whirlline[i], whirlline[i+1], true);
if(whirlline[i]->item) if(whirlline[i]->item)
animateMovement(whirlline[i+1], whirlline[i], LAYER_BOAT); animateMovement(whirlline[i+1], whirlline[i], LAYER_BOAT, NOHINT);
} }
for(int i=0; i<z; i++) for(int i=0; i<z; i++)
pickupMovedItems(whirlline[i]); pickupMovedItems(whirlline[i]);
@ -995,7 +995,7 @@ namespace whirlpool {
if(wfrom && wto && wfrom->wall == waBoat && wto->wall == waSea && !wto->monst) { if(wfrom && wto && wfrom->wall == waBoat && wto->wall == waSea && !wto->monst) {
wfrom->wall = waSea; wto->wall = waBoat; wfrom->wall = waSea; wto->wall = waBoat;
wto->mondir = neighborId(wto, wfrom); 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) { if(wfrom && wto && wfrom->item && !wto->item && wfrom->wall != waBoat) {
@ -1206,7 +1206,7 @@ namespace mirror {
continue; continue;
} }
c->monst = moMimic; c->monst = moMimic;
moveMonster(c2, c); moveMonster(c2, c, m.second.spin);
c2->monst = moNone; c2->monst = moNone;
empathyMove(c, c2, neighborId(c2, c)); empathyMove(c, c2, neighborId(c2, c));
m.second = cw2; m.second = cw2;
@ -1639,7 +1639,7 @@ namespace hive {
// c->monst = moDeadBug, deadbug.push_back(c); // c->monst = moDeadBug, deadbug.push_back(c);
} }
else { else {
moveMonster(c2, c); moveMonster(c2, c, d);
// pheromones! // pheromones!
if(c->land == laHive && c->landparam < 90) c->landparam += 5; if(c->land == laHive && c->landparam < 90) c->landparam += 5;
if(c2->land == laHive && c2->landparam < 90) c2->landparam += 5; if(c2->land == laHive && c2->landparam < 90) c2->landparam += 5;
@ -2297,7 +2297,7 @@ namespace dragon {
mountmove(c, c->mondir, true, c2); mountmove(c, c->mondir, true, c2);
c->monst = c2->monst; c->monst = c2->monst;
c->hitpoints = c2->hitpoints; c->hitpoints = c2->hitpoints;
animateMovement(c2, c, LAYER_BIG); animateMovement(c2, c, LAYER_BIG, c->spin(c->mondir));
c->stuntime = 2; c->stuntime = 2;
if(c2->mondir == NODIR) { c->mondir = NODIR; c2->monst = moNone; return; } if(c2->mondir == NODIR) { c->mondir = NODIR; c2->monst = moNone; return; }
c = c2; c = c2;
@ -2417,7 +2417,7 @@ namespace dragon {
cmt->monst = cft->monst; cmt->monst = cft->monst;
cft->monst = moNone; cft->monst = moNone;
mountmove(cmt, cmt->mondir, true, cft); mountmove(cmt, cmt->mondir, true, cft);
animateMovement(cft, cmt, LAYER_BIG); animateMovement(cft, cmt, LAYER_BIG, allcells[i]->mondir);
} }
while(c->mondir != NODIR) { while(c->mondir != NODIR) {
c = c->mov[c->mondir]; c = c->mov[c->mondir];
@ -2656,7 +2656,7 @@ namespace kraken {
noconflict = false; */ noconflict = false; */
/* if(noconflict) */ { /* if(noconflict) */ {
// found = true; // 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[i] = acells[size(acells)-1];
acells.resize(size(acells)-1); acells.resize(size(acells)-1);
i--; i--;
@ -2872,7 +2872,7 @@ namespace prairie {
} }
if(!cn->monst && !isPlayerOn(cn) && passable_for(cp->monst, cn, cp, P_DEADLY)) if(!cn->monst && !isPlayerOn(cn) && passable_for(cp->monst, cn, cp, P_DEADLY))
moveMonster(cn, cp); moveMonster(cn, cp, NODIR);
else { else {
playSound(NULL, "hit-axe"+pick123()); playSound(NULL, "hit-axe"+pick123());
beastcrash(cn, cp); beastcrash(cn, cp);

View File

@ -337,10 +337,10 @@ namespace conformal {
// virtualRebase(v[j], false); // 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; 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; v[j+1]->at * C0;
hyperpoint hmid = mid(prev, next); 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); v[0]->at = v[0]->at * rspintox(inverse(v[0]->at) * next0);
llv = ticks; llv = ticks;
@ -380,7 +380,7 @@ namespace conformal {
hyperpoint now = v[ph]->at * C0; 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; v[ph+1]->at * C0;
View = spin(M_PI/180 * rotation) * xpush(-(phase-ph) * hdist(now, next)) * View; View = spin(M_PI/180 * rotation) * xpush(-(phase-ph) * hdist(now, next)) * View;
@ -411,7 +411,7 @@ namespace conformal {
for(int j=0; j<siz-1; j++) { for(int j=0; j<siz-1; j++) {
hyperpoint next = hyperpoint next =
inverse(v[j]->at) * inverse(v[j]->at) *
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; v[j+1]->at * C0;
hyperpoint nextscr; hyperpoint nextscr;

View File

@ -110,7 +110,7 @@ void calcMousedest() {
ld dists[MAX_EDGE]; ld dists[MAX_EDGE];
for(int i=0; i<cwt.c->type; i++) for(int i=0; i<cwt.c->type; 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); /* printf("curcell = %Lf\n", mousedist);
for(int i=0; i<cwt.c->type; i++) for(int i=0; i<cwt.c->type; i++)

View File

@ -303,7 +303,7 @@ namespace gp {
hyperpoint nearcorner(cell *c, local_info& li, int i) { hyperpoint nearcorner(cell *c, local_info& li, int i) {
cellwalker cw(c, i); cellwalker cw(c, i);
cw += wstep; 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; if(elliptic && cwm[2][2] < 0) cwm = centralsym * cwm;
return cwm * C0; return cwm * C0;
} }
@ -311,7 +311,7 @@ namespace gp {
hyperpoint hypercorner(cell *c, local_info& li, int i) { hyperpoint hypercorner(cell *c, local_info& li, int i) {
cellwalker cw(c, i); cellwalker cw(c, i);
cw += wstep; 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; if(elliptic && cwm[2][2] < 0) cwm = centralsym * cwm;
auto li1 = get_local_info(cw.c); auto li1 = get_local_info(cw.c);
return cwm * get_corner_position(li1, (cw+2).spin); return cwm * get_corner_position(li1, (cw+2).spin);
@ -358,8 +358,9 @@ namespace gp {
cellwalker cw(c0, c); cellwalker cw(c0, c);
cw += d+sidir+siid+1; cw += d+sidir+siid+1;
int hint = cw.spin;
cw += wstep; 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; hyperpoint nfar = cwm*C0;
auto li1 = get_local_info(cw.c); auto li1 = get_local_info(cw.c);
hyperpoint nlfar = cwm * get_corner_position(li1, (cw+2).spin); hyperpoint nlfar = cwm * get_corner_position(li1, (cw+2).spin);

117
game.cpp
View File

@ -734,18 +734,18 @@ bool canPushStatueOn(cell *c) {
!isWorm(c->monst) && !isReptile(c->wall) && !peace::on; !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; eWall x = to->wall; to->wall = from->wall; from->wall = x;
to->mondir = neighborId(to, from); to->mondir = neighborId(to, from);
moveItem(from, to, false); moveItem(from, to, false);
animateMovement(from, to, LAYER_BOAT); animateMovement(from, to, LAYER_BOAT, direction_hint);
} }
void moveBoatIfUsingOne(cell *to, cell *from) { void moveBoatIfUsingOne(cell *to, cell *from, int direction_hint) {
if(from->wall == waBoat && isWatery(to)) moveBoat(to, from); if(from->wall == waBoat && isWatery(to)) moveBoat(to, from, direction_hint);
else if(from->wall == waBoat && boatGoesThrough(to) && markEmpathy(itOrbWater)) { else if(from->wall == waBoat && boatGoesThrough(to) && markEmpathy(itOrbWater)) {
placeWater(to, from); 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; 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) { void flameHalfvine(cell *c, int val) {
if(itemBurns(c->item)) { if(itemBurns(c->item)) {
@ -2087,7 +2087,7 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) {
} }
if(m == moVineBeast) if(m == moVineBeast)
petrify(c, waVinePlant, m), pcount = 0; 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) { if(m == moBomberbird || m == moTameBomberbird) {
pcount = 0; pcount = 0;
playSound(c, "die-bomberbird"); playSound(c, "die-bomberbird");
@ -2446,8 +2446,8 @@ bool attackMonster(cell *c, flagtype flags, eMonster killer) {
return ntk > tk; return ntk > tk;
} }
void pushMonster(cell *ct, cell *cf) { void pushMonster(cell *ct, cell *cf, int direction_hint) {
moveMonster(ct, cf); moveMonster(ct, cf, direction_hint);
} }
bool destroyHalfvine(cell *c, eWall newwall, int tval) { 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, // this is called from moveMonster, or separately from moveIvy/moveWorm,
// or when a dead bird falls (then m == moDeadBird) // 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); 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) { if(cf && ct->item == itBabyTortoise && !cf->item) {
cf->item = itBabyTortoise; cf->item = itBabyTortoise;
ct->item = itNone; ct->item = itNone;
animateMovement(ct, cf, LAYER_BOAT); animateMovement(ct, cf, LAYER_BOAT, direction_hint);
tortoise::babymap[cf] = tortoise::babymap[ct]; tortoise::babymap[cf] = tortoise::babymap[ct];
tortoise::babymap.erase(ct); tortoise::babymap.erase(ct);
} }
@ -3407,20 +3407,20 @@ void makeTrollFootprints(cell *c) {
c->landparam = turncount + 100; c->landparam = turncount + 100;
} }
void moveMonster(cell *ct, cell *cf) { void moveMonster(cell *ct, cell *cf, int direction_hint) {
eMonster m = cf->monst; eMonster m = cf->monst;
bool fri = isFriendly(cf); bool fri = isFriendly(cf);
if(isDragon(m)) { if(isDragon(m)) {
printf("called for Dragon\n"); printf("called for Dragon\n");
return; 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 // the following line is necessary because otherwise plates disappear only inside the sight range
if(cellUnstable(cf) && !ignoresPlates(m)) { if(cellUnstable(cf) && !ignoresPlates(m)) {
fallingFloorAnimation(cf); fallingFloorAnimation(cf);
cf->wall = waChasm; cf->wall = waChasm;
} }
moveEffect(ct, cf, m); moveEffect(ct, cf, m, direction_hint);
if(ct->wall == waCamelotMoat && if(ct->wall == waCamelotMoat &&
(m == moShark || m == moCShark || m == moGreaterShark)) (m == moShark || m == moCShark || m == moGreaterShark))
achievement_gain("MOATSHARK"); achievement_gain("MOATSHARK");
@ -3460,10 +3460,10 @@ void moveMonster(cell *ct, cell *cf) {
if(ct->wall == waBigStatue) { if(ct->wall == waBigStatue) {
ct->wall = cf->wall; ct->wall = cf->wall;
cf->wall = waBigStatue; 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); } if(isTroll(m)) { makeTrollFootprints(ct); makeTrollFootprints(cf); }
@ -3894,7 +3894,7 @@ int pickDownDirection(cell *c, flagtype mf) {
} }
template<class T> template<class T>
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) { if(subdir != 1 && subdir != -1) {
subdir = 1; subdir = 1;
static bool first = true; 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(valid(push.c)) return push.c;
if(c2->type&1) { if(c2->type&1) {
push = push + wstep - subdir + wstep; push = push + wstep - subdir + wstep;
pushdir = (push+wstep).spin;
if(valid(push.c)) return push.c; if(valid(push.c)) return push.c;
} }
if(gravityLevel(push.c) < gravityLevel(c2)) { 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)) { if(gravityLevel(push.c) < gravityLevel(c2)) {
push = push + wstep + 1 + wstep; push = push + wstep + 1 + wstep;
} }
pushdir = (push+wstep).spin;
if(valid(push.c)) return push.c; if(valid(push.c)) return push.c;
} }
return c2; return c2;
@ -3939,9 +3941,10 @@ void beastAttack(cell *c, bool player) {
if(c2->monst && c2->stuntime) { if(c2->monst && c2->stuntime) {
cellwalker bull (c, d); cellwalker bull (c, d);
int subdir = determinizeBullPush(bull); 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) if(c3 && c3 != c2)
pushMonster(c3, c2); pushMonster(c3, c2, pushdir);
} }
} }
if(c2->wall == waThumperOff) { if(c2->wall == waThumperOff) {
@ -3951,7 +3954,8 @@ void beastAttack(cell *c, bool player) {
if(c2->wall == waThumperOn) { if(c2->wall == waThumperOn) {
cellwalker bull (c, d); cellwalker bull (c, d);
int subdir = determinizeBullPush(bull); 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) if(c3 && c3 != c2)
pushThumper(c2, c3); pushThumper(c2, c3);
} }
@ -4002,13 +4006,13 @@ cell *moveNormal(cell *c, flagtype mf) {
} }
else if(m2) { else if(m2) {
attackMonster(c2, AF_NORMAL | AF_MSG, m); attackMonster(c2, AF_NORMAL | AF_MSG, m);
animateAttack(c, c2, LAYER_SMALL); animateAttack(c, c2, LAYER_SMALL, d);
if(m == moFlailer && m2 == moIllusion) if(m == moFlailer && m2 == moIllusion)
attackMonster(c, 0, m2); attackMonster(c, 0, m2);
return c2; return c2;
} }
moveMonster(c2, c); moveMonster(c2, c, d);
if(m == moRagingBull) beastAttack(c2, false); if(m == moRagingBull) beastAttack(c2, false);
return c2; return c2;
} }
@ -4036,7 +4040,7 @@ cell *moveNormal(cell *c, flagtype mf) {
if(!attacking) for(int i=0; i<nc; i++) { if(!attacking) for(int i=0; i<nc; i++) {
cell *c2 = c->mov[posdir[i]]; cell *c2 = c->mov[posdir[i]];
if(!c->monst) c->monst = m; if(!c->monst) c->monst = m;
moveMonster(c2, c); moveMonster(c2, c, posdir[i]);
if(m == moRagingBull) beastAttack(c2, false); if(m == moRagingBull) beastAttack(c2, false);
} }
return c->mov[d]; 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) { void mountmove(cell *c, int spin, bool fp, cell *ppos) {
for(int i=0; i<numplayers(); i++) { for(int i=0; i<numplayers(); i++) {
if(playerpos(i) == ppos) { if(playerpos(i) == ppos) {
animateMovement(ppos, c, LAYER_SMALL); animateMovement(ppos, c, LAYER_SMALL, revhint(c, spin));
mountmove(c, spin, fp, i); mountmove(c, spin, fp, i);
} }
if(lastmountpos[i] == ppos && ppos != NULL) { if(lastmountpos[i] == ppos && ppos != NULL) {
@ -4213,7 +4217,7 @@ void moveWorm(cell *c) {
cell *cft = allcells[i]; cell *cft = allcells[i];
if(cft->monst != moTentacleGhost && cmt->monst != moTentacleGhost) if(cft->monst != moTentacleGhost && cmt->monst != moTentacleGhost)
mountmove(cmt, cft->spn(cft->mondir), false, cft); mountmove(cmt, cft->spn(cft->mondir), false, cft);
animateMovement(cft, cmt, LAYER_BIG); animateMovement(cft, cmt, LAYER_BIG, cft->mondir);
} }
c->monst = moNone; c->monst = moNone;
if(c->mondir != NODIR) c->mov[c->mondir]->monst = moTentacleEscaping; if(c->mondir != NODIR) c->mov[c->mondir]->monst = moTentacleEscaping;
@ -4283,9 +4287,9 @@ void moveWorm(cell *c) {
for(int j=0; j<c->type; j++) if(c->mov[j] == goal) { for(int j=0; j<c->type; j++) if(c->mov[j] == goal) {
goal->monst = eMonster(moWormwait + id); 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); c->monst = eMonster(moWormtail + id);
goal->mondir = c->spn(j); goal->mondir = c->spn(j);
@ -4301,7 +4305,7 @@ void moveWorm(cell *c) {
c3 = c2, c2 = c3->mov[c2->mondir]; c3 = c2, c2 = c3->mov[c2->mondir];
if(c3->monst != moTentacleGhost && c2->monst != moTentacleGhost) if(c3->monst != moTentacleGhost && c2->monst != moTentacleGhost)
mountmove(c3, c3->mondir, true, c2); 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]; c3 = c2, c2 = c3->mov[c2->mondir];
mountmove(c3, c3->mondir, true, c2); 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) { 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; 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 this is the only branch, we want to move the head immediately to mto instead
if(mto->mov[mto->mondir]->monst == moIvyHead) { if(mto->mov[mto->mondir]->monst == moIvyHead) {
mto->monst = moIvyHead; co->monst = moIvyBranch; 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; j<c->type; j++) if(!(mf & MF_NOATTACKS)) for(int j=0; j<c->type; j++)
if(c->mov[j] && canAttack(c, c->monst, c->mov[j], c->mov[j]->monst, af)) { 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); 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; c->aitmp = sval;
// XLATC eagle // XLATC eagle
return; return;
@ -4540,7 +4544,7 @@ void groupmove2(cell *c, cell *from, int d, eMonster movtype, flagtype mf) {
return; return;
} }
moveMonster(from, c); moveMonster(from, c, revhint(from, d));
from->aitmp = sval; from->aitmp = sval;
} }
c->aitmp = sval; c->aitmp = sval;
@ -4612,12 +4616,12 @@ vector<cell*> hexdfs;
// note: move from 'c' to 'from'! // note: move from 'c' to 'from'!
void moveHexSnake(cell *from, cell *c, int d, bool mounted) { void moveHexSnake(cell *from, cell *c, int d, bool mounted) {
if(from->wall == waBoat) from->wall = waSea; 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; from->monst = c->monst; from->mondir = d; from->hitpoints = c->hitpoints;
c->monst = moHexSnakeTail; c->monst = moHexSnakeTail;
preventbarriers(from); preventbarriers(from);
animateMovement(c, from, LAYER_BIG); animateMovement(c, from, LAYER_BIG, revhint(from, d));
mountmove(from, from->mondir, true, c); mountmove(from, from->mondir, true, c);
cell *c2 = c, *c3=c2; 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(a == ROCKSNAKELENGTH) { c2->monst = moNone, c3->mondir = NODIR; break; }
if(c2->mondir == NODIR) break; if(c2->mondir == NODIR) break;
mountmove(c2, c2->mondir, true, c2->mov[c2->mondir]); 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]; c3 = c2, c2 = c3->mov[c2->mondir];
} }
else break; else break;
@ -4787,7 +4791,7 @@ void movemutant() {
c2->monst = moMutant; c2->monst = moMutant;
c2->mondir = c->spn(j); c2->mondir = c->spn(j);
c2->stuntime = mutantphase; 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]; cell* where = shpos[p][cshpos];
if(where && where->monst == moNone && where->cpdist && where->land == laGraveyard && if(where && where->monst == moNone && where->cpdist && where->land == laGraveyard &&
!sword::at(where)) { !sword::at(where)) {
if(shfrom) animateMovement(shfrom, where, LAYER_SMALL); if(shfrom) animateMovement(shfrom, where, LAYER_SMALL, NOHINT);
where->monst = moShadow; where->monst = moShadow;
where->hitpoints = p; where->hitpoints = p;
where->stuntime = 0; where->stuntime = 0;
@ -4881,7 +4885,7 @@ void moveghosts() {
addMessage(XLAT("%The1 scares %the2 a bit!", c->monst, c2->monst)); addMessage(XLAT("%The1 scares %the2 a bit!", c->monst, c2->monst));
c2->stuntime = 1; c2->stuntime = 1;
} }
else moveMonster(c2, c); else moveMonster(c2, c, d);
} }
nextghost: ; 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)) else if((flags & AF_CRUSH) && !canAttack(c, m, c2, c2->monst, flags ^ AF_CRUSH ^ AF_MUSTKILL))
markOrb(itOrbEmpathy), markOrb(itOrbSlaying); markOrb(itOrbEmpathy), markOrb(itOrbSlaying);
attackMonster(c2, flags | AF_MSG, m); attackMonster(c2, flags | AF_MSG, m);
animateAttack(c, c2, LAYER_SMALL); animateAttack(c, c2, LAYER_SMALL, dir);
produceGhost(c2, m2, m); produceGhost(c2, m2, m);
sideAttack(c, dir, m, 0); sideAttack(c, dir, m, 0);
if(revenge) c->monst = m = moPrincessArmed; if(revenge) c->monst = m = moPrincessArmed;
@ -5261,9 +5265,9 @@ void movegolems(flagtype flags) {
else { else {
passable_for(m, c2, c, P_DEADLY); passable_for(m, c2, c, P_DEADLY);
DEBT("move"); DEBT("move");
moveMonster(c2, c); moveMonster(c2, c, dir);
if(m != moTameBomberbird && m != moFriendlyGhost) if(m != moTameBomberbird && m != moFriendlyGhost)
moveBoatIfUsingOne(c2, c); moveBoatIfUsingOne(c2, c, dir);
if(c2->monst == m) { if(c2->monst == m) {
if(m == moGolem) c2->monst = moGolemMoved; 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)) { 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(c3 == c2) {
if(checkonly) return false; if(checkonly) return false;
addMessage(XLAT("No room to push %the1.", c2->wall)); 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; if(checkonly) return true;
moveBoat(c2, cwt.c); moveBoat(c2, cwt.c, d);
boatmove = true; boatmove = true;
goto boatjump; goto boatjump;
} }
@ -7462,8 +7467,8 @@ bool movepcto(int d, int subdir, bool checkonly) {
if(checkonly) return true; if(checkonly) return true;
if(c2->item && !cwt.c->item) moveItem(c2, cwt.c, false), boatmove = true; if(c2->item && !cwt.c->item) moveItem(c2, cwt.c, false), boatmove = true;
placeWater(c2, cwt.c); placeWater(c2, cwt.c);
moveBoat(c2, cwt.c); moveBoat(c2, cwt.c, d);
c2->mondir = neighborId(c2, cwt.c); c2->mondir = revhint(cwt.c, d);
if(c2->item) boatmove = !boatmove; if(c2->item) boatmove = !boatmove;
goto boatjump; 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; } if(checkonly) { c2->wall = save_c2; cwt.c->wall = save_cw; return true; }
addMessage(XLAT("You push %the1 behind you!", waBigStatue)); 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; goto statuejump;
} }
@ -7522,7 +7527,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
playSound(c2, "hit-axe" + pick123()); playSound(c2, "hit-axe" + pick123());
c2->wall = waNone; c2->wall = waNone;
sideAttack(cwt.c, d, moPlayer, 0); sideAttack(cwt.c, d, moPlayer, 0);
animateAttack(cwt.c, c2, LAYER_SMALL); animateAttack(cwt.c, c2, LAYER_SMALL, d);
} }
else if(c2->wall == waBigTree) { else if(c2->wall == waBigTree) {
drawParticles(c2, winf[c2->wall].color, 8); drawParticles(c2, winf[c2->wall].color, 8);
@ -7530,13 +7535,13 @@ bool movepcto(int d, int subdir, bool checkonly) {
playSound(c2, "hit-axe" + pick123()); playSound(c2, "hit-axe" + pick123());
c2->wall = waSmallTree; c2->wall = waSmallTree;
sideAttack(cwt.c, d, moPlayer, 0); sideAttack(cwt.c, d, moPlayer, 0);
animateAttack(cwt.c, c2, LAYER_SMALL); animateAttack(cwt.c, c2, LAYER_SMALL, d);
} }
else { else {
if(!peace::on) { if(!peace::on) {
addMessage(XLAT("You swing your sword at the mirror.")); addMessage(XLAT("You swing your sword at the mirror."));
sideAttack(cwt.c, d, moPlayer, 0); sideAttack(cwt.c, d, moPlayer, 0);
animateAttack(cwt.c, c2, LAYER_SMALL); animateAttack(cwt.c, c2, LAYER_SMALL, d);
} }
} }
if(survivalist && isHaunted(c2->land)) 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 // pushto=c2 means that the monster is not killed and thus
// still counts for lightning in monstersnear // still counts for lightning in monstersnear
cell *pushto = NULL; cell *pushto = NULL;
int pushdir = 0;
if(isStunnable(c2->monst) && c2->hitpoints > 1) { if(isStunnable(c2->monst) && c2->hitpoints > 1) {
if(monsterPushable(c2)) 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 else
pushto = c2; 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 // salamanders are stunned for longer time when pushed into a wall
if(c2->monst == moSalamander && (pushto == c2 || !pushto)) c2->stuntime = 10; if(c2->monst == moSalamander && (pushto == c2 || !pushto)) c2->stuntime = 10;
if(!c2->monst) produceGhost(c2, m, moPlayer); if(!c2->monst) produceGhost(c2, m, moPlayer);
if(pushto && pushto != c2) pushMonster(pushto, c2); if(pushto && pushto != c2) pushMonster(pushto, c2, pushdir);
animateAttack(cwt.c, c2, LAYER_SMALL); animateAttack(cwt.c, c2, LAYER_SMALL, d);
} }
} }
@ -7840,11 +7846,12 @@ bool movepcto(int d, int subdir, bool checkonly) {
stabbingAttack(cwt.c, c2, moPlayer); stabbingAttack(cwt.c, c2, moPlayer);
cell *c1 = cwt.c; cell *c1 = cwt.c;
int d = cwt.spin;
cwt += wstep; cwt += wstep;
if(switchplaces) if(switchplaces)
animateReplacement(c1, cwt.c, LAYER_SMALL); animateReplacement(c1, cwt.c, LAYER_SMALL, d, cwt.spin);
else else
animateMovement(c1, cwt.c, LAYER_SMALL); animateMovement(c1, cwt.c, LAYER_SMALL, d);
mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK | mirror::GO); mirror::act(origd, mirror::SPINMULTI | mirror::ATTACK | mirror::GO);

View File

@ -2090,7 +2090,7 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) {
Vb = Vb * xpush(tentacle_length - cellgfxdist(c, c->mondir)); Vb = Vb * xpush(tentacle_length - cellgfxdist(c, c->mondir));
} }
else if(gp::on) { 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); Vb = Vb * T * rspintox(tC0(inverse(T))) * xpush(tentacle_length);
} }
else { else {
@ -2139,6 +2139,10 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) {
Vs = playerV; Vs = playerV;
if(multi::players > 1 ? multi::flipped[i] : flipplayer) Vs = Vs * pispin; 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; shmup::cpid = i;
drawPlayerEffects(Vs, c, true); drawPlayerEffects(Vs, c, true);
@ -2562,7 +2566,7 @@ void drawMovementArrows(cell *c, transmatrix V) {
int sd = md.subdir; 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); 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((vid.axes == 4 || (vid.axes == 1 && !mousing)) && !shmup::on) {
if(multi::players == 1) { 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<multi::players; p++) { else if(multi::players > 1) for(int p=0; p<multi::players; p++) {
if(multi::playerActive(p) && (vid.axes == 4 || !drawstaratvec(multi::mdx[p], multi::mdy[p]))) if(multi::playerActive(p) && (vid.axes == 4 || !drawstaratvec(multi::mdx[p], multi::mdy[p])))
forCellAll(c2, multi::player[p].c) IG(c2) { forCellIdAll(c2, d, multi::player[p].c) IG(c2) {
multi::cpid = p; multi::cpid = p;
dynamicval<transmatrix> ttm(cwtV, multi::whereis[p]); dynamicval<transmatrix> ttm(cwtV, multi::whereis[p]);
dynamicval<cellwalker> tcw(cwt, multi::player[p]); dynamicval<cellwalker> 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<cell*, animation> animations[ANIMLAYERS]; map<cell*, animation> animations[ANIMLAYERS];
unordered_map<cell*, transmatrix> gmatrix, gmatrix0; unordered_map<cell*, transmatrix> 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(vid.mspeed >= 5) return; // no animations!
if(confusingGeometry()) return; transmatrix T;
if(gmatrix.count(src) && gmatrix.count(tgt)) { if(!compute_relamatrix(src, tgt, direction_hint, T)) return;
animation& a = animations[layer][tgt]; animation& a = animations[layer][tgt];
if(animations[layer].count(src)) { if(animations[layer].count(src)) {
a = animations[layer][src]; a = animations[layer][src];
a.wherenow = inverse(gmatrix[tgt]) * gmatrix[src] * a.wherenow; a.wherenow = T * a.wherenow;
animations[layer].erase(src); animations[layer].erase(src);
a.attacking = 0; a.attacking = 0;
} }
else { else {
a.ltick = ticks; a.ltick = ticks;
a.wherenow = inverse(gmatrix[tgt]) * gmatrix[src]; a.wherenow = T;
a.footphase = 0; 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(vid.mspeed >= 5) return; // no animations!
if(gmatrix.count(src) && gmatrix.count(tgt)) { transmatrix T;
bool newanim = !animations[layer].count(src); if(!compute_relamatrix(src, tgt, direction_hint, T)) return;
animation& a = animations[layer][src]; bool newanim = !animations[layer].count(src);
a.attacking = 1; animation& a = animations[layer][src];
a.attackat = rspintox(tC0(inverse(gmatrix[src]) * gmatrix[tgt])) * xpush(hdist(gmatrix[src]*C0, gmatrix[tgt]*C0) / 3); a.attacking = 1;
if(newanim) a.wherenow = Id, a.ltick = ticks, a.footphase = 0; a.attackat = rspintox(tC0(inverse(T))) * xpush(hdist0(T*C0) / 3);
} if(newanim) a.wherenow = Id, a.ltick = ticks, a.footphase = 0;
} }
vector<pair<cell*, animation> > animstack; vector<pair<cell*, animation> > 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(vid.mspeed >= 5) return; // no animations!
if(confusingGeometry()) return;
if(animations[layer].count(tgt)) { if(animations[layer].count(tgt)) {
animation res = animations[layer][tgt]; animation res = animations[layer][tgt];
animations[layer].erase(tgt); animations[layer].erase(tgt);
animateMovement(src, tgt, layer); animateMovement(src, tgt, layer, direction_hint);
if(animations[layer].count(tgt)) if(animations[layer].count(tgt))
animstack.push_back(make_pair(tgt, animations[layer][tgt])); animstack.push_back(make_pair(tgt, animations[layer][tgt]));
animations[layer][tgt] = res; animations[layer][tgt] = res;
} }
else { else {
animateMovement(src, tgt, layer); animateMovement(src, tgt, layer, direction_hint);
if(animations[layer].count(tgt)) { if(animations[layer].count(tgt)) {
animstack.push_back(make_pair(tgt, animations[layer][tgt])); animstack.push_back(make_pair(tgt, animations[layer][tgt]));
animations[layer].erase(tgt); animations[layer].erase(tgt);
@ -5798,13 +5819,13 @@ void commitAnimations(int layer) {
animstack.clear(); 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! if(vid.mspeed >= 5) return; // no animations!
static cell c1; static cell c1;
gmatrix[&c1] = gmatrix[b]; gmatrix[&c1] = gmatrix[b];
if(animations[layer].count(b)) animations[layer][&c1] = animations[layer][b]; if(animations[layer].count(b)) animations[layer][&c1] = animations[layer][b];
animateMovement(a, b, layer); animateMovement(a, b, layer, direction_hinta);
animateMovement(&c1, a, layer); animateMovement(&c1, a, layer, direction_hintb);
} }
void drawBug(const cellwalker& cw, int col) { void drawBug(const cellwalker& cw, int col) {

19
hyper.h
View File

@ -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); void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill = 0);
bool earthMove(cell *from, int dir); bool earthMove(cell *from, int dir);
void messageKill(eMonster killer, eMonster victim); void messageKill(eMonster killer, eMonster victim);
void moveMonster(cell *ct, cell *cf); void moveMonster(cell *ct, cell *cf, int direction_hint);
int palaceHP(); int palaceHP();
void placeLocalOrbs(cell *c); void placeLocalOrbs(cell *c);
int elementalKills(); int elementalKills();
@ -652,7 +652,7 @@ namespace shmup {
void virtualRebase(cell*& base, transmatrix& at, bool tohex); void virtualRebase(cell*& base, transmatrix& at, bool tohex);
void virtualRebase(shmup::monster *m, 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 fixStorage();
void addShmupHelp(string& out); void addShmupHelp(string& out);
void activateArrow(cell *c); void activateArrow(cell *c);
@ -663,6 +663,8 @@ namespace shmup {
void popmonsters(); void popmonsters();
} }
static const int NOHINT = -1;
// graph // graph
void showMissionScreen(); void showMissionScreen();
@ -1550,16 +1552,16 @@ struct animation {
extern map<cell*, animation> animations[ANIMLAYERS]; extern map<cell*, animation> animations[ANIMLAYERS];
extern unordered_map<cell*, transmatrix> gmatrix, gmatrix0; extern unordered_map<cell*, transmatrix> 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, // for animations which might use the same locations,
// such as replacements or multi-tile monsters // 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 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 fallingFloorAnimation(cell *c, eWall w = waNone, eMonster m = moNone);
void fallingMonsterAnimation(cell *c, eMonster m, int id = multi::cpid); void fallingMonsterAnimation(cell *c, eMonster m, int id = multi::cpid);
@ -2778,7 +2780,6 @@ namespace texture {
void showMenu(); void showMenu();
void drawPixel(cell *c, hyperpoint h, int col); void drawPixel(cell *c, hyperpoint h, int col);
extern cell *where; extern cell *where;
// compute 'c' automatically, based on the hint in 'where' // compute 'c' automatically, based on the hint in 'where'
void drawPixel(hyperpoint h, int col); void drawPixel(hyperpoint h, int col);
@ -3502,4 +3503,8 @@ void gdpush(int t);
extern int fontscale; extern int fontscale;
bool confusingGeometry();
int revhint(cell *c, int hint);
} }

View File

@ -577,7 +577,7 @@ void jumpTo(cell *dest, eItem byWhat, int bonuskill, eMonster dashmon) {
killFriendlyIvy(); killFriendlyIvy();
cell *c1 = cwt.c; cell *c1 = cwt.c;
animateMovement(cwt.c, dest, LAYER_SMALL); animateMovement(cwt.c, dest, LAYER_SMALL, NOHINT);
cwt.c = dest; cwt.c = dest;
forCellIdEx(c2, i, dest) if(c2->cpdist < dest->cpdist) { forCellIdEx(c2, i, dest) if(c2->cpdist < dest->cpdist) {
cwt.spin = i; cwt.spin = i;
@ -619,13 +619,13 @@ void jumpTo(cell *dest, eItem byWhat, int bonuskill, eMonster dashmon) {
monstersTurn(); monstersTurn();
} }
void growIvyTo(cell *dest, cell *src) { void growIvyTo(cell *dest, cell *src, int direction_hint) {
if(dest->monst) if(dest->monst)
attackMonster(dest, AF_NORMAL | AF_MSG, moFriendlyIvy); attackMonster(dest, AF_NORMAL | AF_MSG, moFriendlyIvy);
else { else {
dest->monst = moFriendlyIvy; dest->monst = moFriendlyIvy;
dest->mondir = neighborId(dest, src); dest->mondir = neighborId(dest, src);
moveEffect(dest, src, moFriendlyIvy); moveEffect(dest, src, moFriendlyIvy, direction_hint);
empathyMove(src, dest, neighborId(src, dest)); empathyMove(src, dest, neighborId(src, dest));
} }
createNoise(1); createNoise(1);
@ -797,7 +797,7 @@ void summonAt(cell *dest) {
if(dest->monst == moTortoise) if(dest->monst == moTortoise)
tortoise::emap[dest] = dest; tortoise::emap[dest] = dest;
addMessage(XLAT("You summon %the1!", dest->monst)); 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) if(dest->wall == waClosePlate || dest->wall == waOpenPlate)
toggleGates(dest, dest->wall); toggleGates(dest, dest->wall);
@ -865,7 +865,7 @@ void gun_attack(cell *dest) {
void checkStunKill(cell *dest) { void checkStunKill(cell *dest) {
if(isBird(dest->monst)) { if(isBird(dest->monst)) {
moveEffect(dest, dest, moDeadBird); moveEffect(dest, dest, moDeadBird, NOHINT);
doesFall(dest); doesFall(dest);
if(isWatery(dest) || dest->wall == waChasm || isFire(dest)) { if(isWatery(dest) || dest->wall == waChasm || isFire(dest)) {
addMessage(XLAT("%The1 falls!", dest->monst)); addMessage(XLAT("%The1 falls!", dest->monst));
@ -925,10 +925,10 @@ void placeIllusion(cell *c) {
checkmoveO(); checkmoveO();
} }
void blowoff(cell *cf, cell *ct) { void blowoff(cell *cf, cell *ct, int direction_hint) {
playSound(ct, "orb-ranged"); playSound(ct, "orb-ranged");
addMessage(XLAT("You blow %the1 away!", cf->monst)); addMessage(XLAT("You blow %the1 away!", cf->monst));
pushMonster(ct, cf); pushMonster(ct, cf, direction_hint);
if(cf->item == itBabyTortoise && !ct->item) if(cf->item == itBabyTortoise && !ct->item)
moveItem(cf, ct, true); moveItem(cf, ct, true);
items[itOrbAir]--; items[itOrbAir]--;
@ -1024,9 +1024,10 @@ eItem targetRangedOrb(cell *c, orbAction a) {
for(; d<c->type; d++) if(c->mov[d] && c->mov[d]->cpdist < c->cpdist) break; for(; d<c->type; d++) if(c->mov[d] && c->mov[d]->cpdist < c->cpdist) break;
if(d<c->type) for(int e=d; e<d+c->type; e++) { if(d<c->type) for(int e=d; e<d+c->type; e++) {
nowhereToBlow = true; 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(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; return itOrbAir;
} }
} }
@ -1035,8 +1036,9 @@ eItem targetRangedOrb(cell *c, orbAction a) {
// nature // nature
if(items[itOrbNature] && numplayers() == 1 && c->monst != moFriendlyIvy) { if(items[itOrbNature] && numplayers() == 1 && c->monst != moFriendlyIvy) {
cell *sides[8]; cell *sides[8];
int dirs[8];
int qsides = 0; int qsides = 0;
forCellCM(cf, c) forCellIdCM(cf, d, c)
if(cf->monst == moFriendlyIvy) { if(cf->monst == moFriendlyIvy) {
if(c->monst) { if(c->monst) {
@ -1048,11 +1050,13 @@ eItem targetRangedOrb(cell *c, orbAction a) {
if(strictlyAgainstGravity(c, cf, false, MF_IVY)) continue; if(strictlyAgainstGravity(c, cf, false, MF_IVY)) continue;
if(monstersnear(cwt.c, NULL, moPlayer, c, cwt.c)) continue; if(monstersnear(cwt.c, NULL, moPlayer, c, cwt.c)) continue;
} }
dirs[qsides] = d;
sides[qsides++] = cf; sides[qsides++] = cf;
} }
if(qsides > 0) { 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; return itOrbNature;
} }
} }

View File

@ -334,7 +334,7 @@ void bantar_frame() {
View = Id; 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; if(tphase < 2) part = 0;
else if(tphase == 2) else if(tphase == 2)

View File

@ -1624,7 +1624,7 @@ void movePlayer(monster *m, int delta) {
m->base->wall = waChasm; m->base->wall = waChasm;
else { else {
m->base->wall = waBigStatue; 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)) { 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; m->base->wall = waChasm;
else else
m->base->wall = waBigStatue; 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(passable_for(m->type, c2, m->base, P_CHAIN | P_ONPLAYER | reflectflag) && !isWatery(c2) && m->inBoat) {
if(isWatery(m->base)) if(isWatery(m->base))
@ -3336,7 +3336,7 @@ transmatrix master_relative(cell *c, bool get_inverse) {
return T; return T;
} }
} }
else if(!nonbitrunc) { else if(!nonbitrunc && !euclid) {
for(int d=0; d<S7; d++) if(c->master->c7->mov[d] == c) for(int d=0; d<S7; d++) if(c->master->c7->mov[d] == c)
return (get_inverse?invhexmove:hexmove)[d]; return (get_inverse?invhexmove:hexmove)[d];
return Id; return Id;
@ -3345,7 +3345,8 @@ transmatrix master_relative(cell *c, bool get_inverse) {
return pispin * Id; 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(sphere) {
if(!gmatrix0.count(c2) || !gmatrix0.count(c1)) { if(!gmatrix0.count(c2) || !gmatrix0.count(c1)) {
@ -3358,14 +3359,46 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1) {
swap(gmatrix, gmatrix0); swap(gmatrix, gmatrix0);
gp::draw_li = bak; gp::draw_li = bak;
} }
if(gmatrix0.count(c2) && gmatrix0.count(c1)) if(gmatrix0.count(c2) && gmatrix0.count(c1)) {
return inverse(gmatrix0[c1]) * gmatrix0[c2]; transmatrix T = inverse(gmatrix0[c1]) * gmatrix0[c2];
if(elliptic && T[2][2] < 0)
T = centralsym * T;
return T;
}
else { else {
printf("error: gmatrix0 not known\n"); printf("error: gmatrix0 not known\n");
return Id; 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; heptagon *h1 = c1->master;
transmatrix gm = master_relative(c1, true); transmatrix gm = master_relative(c1, true);
heptagon *h2 = c2->master; heptagon *h2 = c2->master;
@ -3375,20 +3408,26 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1) {
//bool hsol = false; //bool hsol = false;
//transmatrix sol; //transmatrix sol;
while(h1 != h2) { while(h1 != h2) {
int confusion = 0; if(quotient == 1) {
if(quotient == 1 && gp::on) { transmatrix T;
for(int d=0; d<S7; d++) if(h2->move[d] == h1) confusion++; hyperpoint hint = ddspin(c1, direction_hint) * xpush(1e-2) * C0;
if(confusion > 1) { ld bestdist = 1e9;
transmatrix T; for(int d=0; d<S7; d++) if(h2->move[d]) {
confusion = 0; int sp = h2->spin(d);
for(int d=0; d<S7; d++) if(h2->move[d] == h1) { transmatrix S = heptmove[sp] * spin(2*M_PI*d/S7);
int sp = h2->spin(d); if(h2->move[d] == h1) {
transmatrix T1 = gm * heptmove[sp] * spin(2*M_PI*d/S7) * where; transmatrix T1 = gm * S * where;
if(confusion == 0 || T1[2][2] < T[2][2]) T = T1; auto curdist = hdist(tC0(T1), hint);
confusion++; if(curdist < bestdist) T = T1, bestdist = curdist;
}
for(int e=0; e<S7; e++) if(h2->move[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; d<S7; d++) if(h2->move[d] == h1) { for(int d=0; d<S7; d++) if(h2->move[d] == h1) {
int sp = h2->spin(d); int sp = h2->spin(d);
@ -3421,17 +3460,14 @@ transmatrix calc_relative_matrix(cell *c2, cell *c1) {
transmatrix &ggmatrix(cell *c) { transmatrix &ggmatrix(cell *c) {
transmatrix& t = gmatrix[c]; transmatrix& t = gmatrix[c];
if(t[2][2] == 0) { if(t[2][2] == 0) {
if(torus) { if(torus && centerover.c)
forCellIdEx(c2, i, c) t = calc_relative_matrix(c, centerover.c, NOHINT);
if(celldistance(c2, centerover.c) < celldistance(c, centerover.c))
t = ggmatrix(c2) * eumovedir(3+i);
}
else if(euclid) { else if(euclid) {
if(!centerover.c) centerover = cwt; if(!centerover.c) centerover = cwt;
t = View * eumove(cell_to_vec(c) - cellwalker_to_vec(centerover)); t = View * eumove(cell_to_vec(c) - cellwalker_to_vec(centerover));
} }
else 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; return t;
} }