1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-24 17:10:36 +00:00

Merge branch 'master' into makefile-fixes

This commit is contained in:
Zeno Rogue 2018-06-17 18:22:20 +02:00 committed by GitHub
commit b6f47dd907
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 278 additions and 175 deletions

View File

@ -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);
}

View File

@ -1362,16 +1362,17 @@ map<pair<cell*, cell*>, int> saved_distances;
int celldistance(cell *c1, cell *c2) {
int d = 0;
if(euclid) {
if(torus)
if(euclid6) {
if(!torus)
return eudist(decodeId(c1->master) - decodeId(c2->master));
else if(torus && torusconfig::torus_mode == 0)
return torusmap()->dists[torusconfig::vec_to_id(decodeId(c1->master)-decodeId(c2->master))];
return eudist(decodeId(c1->master) - decodeId(c2->master));
}
if(quotient == 2 && !gp::on)
return currfp.getdist(fieldpattern::fieldval(c1), fieldpattern::fieldval(c2));
if(sphere || quotient) {
if(sphere || quotient || torus) {
if(saved_distances.count(make_pair(c1,c2)))
return saved_distances[make_pair(c1,c2)];

View File

@ -2489,3 +2489,8 @@ non-game:
- uniformized the 'back' and 'help' options in menu (consistent hotkeys, consistent placement, added them where they were missing)
- pushing a thumper through a stranded boat is no longer allowed
- fixed a bug with pushing Thumpers through tentacles
2018.06.14 16:39
- fixed viewing the "past challenges"
- fixed a bug which sometimes caused current scores to be copied to past challenge leaderboards.

View File

@ -136,7 +136,7 @@ namespace whirlwind {
for(int i=0; i<z-1; i++) {
moveItem(whirlline[i], whirlline[i+1], true);
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++)
pickupMovedItems(whirlline[i]);
@ -995,7 +995,7 @@ namespace whirlpool {
if(wfrom && wto && wfrom->wall == 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);

View File

@ -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; j<siz-1; j++) {
hyperpoint next =
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;
hyperpoint nextscr;

View File

@ -110,7 +110,7 @@ void calcMousedest() {
ld dists[MAX_EDGE];
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);
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) {
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);

119
game.cpp
View File

@ -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<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) {
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; i<nc; i++) {
cell *c2 = c->mov[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; i<numplayers(); i++) {
if(playerpos(i) == ppos) {
animateMovement(ppos, c, LAYER_SMALL);
animateMovement(ppos, c, LAYER_SMALL, revhint(c, spin));
mountmove(c, spin, fp, i);
}
if(lastmountpos[i] == ppos && ppos != NULL) {
@ -4213,7 +4217,7 @@ void moveWorm(cell *c) {
cell *cft = allcells[i];
if(cft->monst != 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; j<c->type; 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; j<c->type; 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<cell*> 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);
from->monst = c->monst; from->mondir = d;
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);

View File

@ -579,14 +579,17 @@ namespace hr { namespace gp {
dialog::init(XLAT("Goldberg"));
bool show_nonthree = !(texture_remap && (S7&1));
bool show_bitrunc = !(texture_remap && !(S7&1));
if(show_nonthree) {
dialog::addBoolItem(XLAT("OFF"), param == loc(1,0), 'a');
dialog::lastItem().value = "GP(1,0)";
}
dialog::addBoolItem(XLAT("bitruncated"), param == loc(1,1), 'b');
dialog::lastItem().value = "GP(1,1)";
if(show_bitrunc) {
dialog::addBoolItem(XLAT("bitruncated"), param == loc(1,1), 'b');
dialog::lastItem().value = "GP(1,1)";
}
if(show_nonthree) {
dialog::addBoolItem(XLAT("chamfered"), param == loc(2,0), 'c');
@ -599,10 +602,12 @@ namespace hr { namespace gp {
dialog::addBreak(100);
dialog::addSelItem("x", its(config.first), 'x');
dialog::addSelItem("y", its(config.second), 'y');
if((config.first-config.second)%3 && !show_nonthree)
dialog::addInfo("This pattern needs x-y divisible by 3");
else
dialog::addInfo(XLAT("This pattern needs x-y divisible by 3"));
else if(config == loc(1,1) && !show_bitrunc)
dialog::addInfo(XLAT("Select bitruncated from the previous menu"));
else
dialog::addBoolItem(XLAT("select"), param == internal_representation(config), 'f');
dialog::addBreak(100);
@ -610,17 +615,17 @@ namespace hr { namespace gp {
dialog::addBack();
dialog::display();
keyhandler = [show_nonthree, texture_remap] (int sym, int uni) {
keyhandler = [show_nonthree, show_bitrunc, texture_remap] (int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(uni == 'a' && show_nonthree)
whirl_set(loc(1, 0), texture_remap);
else if(uni == 'b')
else if(uni == 'b' && show_bitrunc)
whirl_set(loc(1, 1), texture_remap);
else if(uni == 'c' && show_nonthree)
whirl_set(loc(2, 0), texture_remap);
else if(uni == 'd')
whirl_set(loc(3, 0), texture_remap);
else if(uni == 'f' && (show_nonthree || (config.first-config.second)%3 == 0))
else if(uni == 'f' && (config == loc(1,1) ? show_bitrunc : (show_nonthree || (config.first-config.second)%3 == 0)))
whirl_set(config, texture_remap);
else if(uni == 'x')
dialog::editNumber(config.first, 1, 10, 1, 1, "x", helptext());

View File

@ -1826,7 +1826,7 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) {
if(isIvy(c) || isWorm(c) || isMutantIvy(c) || c->monst == moFriendlyIvy) {
if((m == moHexSnake || m == moHexSnakeTail) && c->land == laSnakeNest) {
if((m == moHexSnake || m == moHexSnakeTail) && c->hitpoints == 2) {
int d = c->mondir;
if(d == NODIR)
forCellIdEx(c2, i, c)
@ -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;
}
}
}
@ -3425,6 +3429,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
#if CAP_TEXTURE
if(texture::saving) {
texture::config.apply(c, V, 0xFFFFFFFF);
draw_qfi(c, V, 0xFFFFFFFF);
return;
}
#endif
@ -4962,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<multi::players; 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;
dynamicval<transmatrix> ttm(cwtV, multi::whereis[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));
}
}
}
@ -5739,51 +5744,68 @@ void resetGeometry() {
map<cell*, animation> animations[ANIMLAYERS];
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(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<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(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);
@ -5797,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) {

25
hyper.h
View File

@ -2,9 +2,9 @@
// It is quite chaotic.
// version numbers
#define VER "10.4b"
#define VERNUM 10402
#define VERNUM_HEX 0xA0B2
#define VER "10.4c"
#define VERNUM 10403
#define VERNUM_HEX 0xA0B3
#include <stdarg.h>
@ -480,7 +480,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();
@ -654,7 +654,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);
@ -665,6 +665,8 @@ namespace shmup {
void popmonsters();
}
static const int NOHINT = -1;
// graph
void showMissionScreen();
@ -1552,16 +1554,16 @@ struct animation {
extern map<cell*, animation> animations[ANIMLAYERS];
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,
// 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);
@ -2780,7 +2782,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);
@ -3512,4 +3513,8 @@ void gdpush(int t);
extern int fontscale;
bool confusingGeometry();
int revhint(cell *c, int hint);
}

View File

@ -1626,7 +1626,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
for(int t=0; t<c->type; t++) if(c->mov[t]->mpdist > c->mpdist && !pseudohept(c->mov[t]))
i = t;
if(i != -1 && !peace::on)
generateSnake(c, i);
generateSnake(c, i, 1);
}
else if(hrand(16000) < 50+items[itRedGem]+yendor::hardness() && (nonbitrunc?hrand(10)<3:!ishept(c)) && !c->monst)
c->monst = moRedTroll,
@ -1641,7 +1641,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
for(int t=0; t<c->type; t++) if(c->mov[t]->mpdist > c->mpdist)
gooddir.push_back(t);
if(size(gooddir))
generateSnake(c, gooddir[hrand(size(gooddir))]);
generateSnake(c, gooddir[hrand(size(gooddir))], 2);
}
else if(hrand(10000) < items[itSnake] - 10 + yendor::hardness() && !c->monst && !c->wall && !peace::on) {
c->monst = pick(moRedTroll, moMiner, moSkeleton, moBomberbird);
@ -1970,7 +1970,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
c->monst = moMonkey;
else if(hrand(80000) < 5 + items[itRuby] + yendor::hardness())
c->monst = moEagle;
else if(ishept(c) && c != currentmap->gamestart() && hrand(4000) < 300 + items[itRuby] && !c->monst) {
else if(pseudohept(c) && c != currentmap->gamestart() && hrand(4000) < 300 + items[itRuby] && !c->monst) {
int hardchance = items[itRuby] + yendor::hardness();
if(hardchance > 25) hardchance = 25;
bool hardivy = hrand(100) < hardchance;

View File

@ -547,6 +547,12 @@ namespace mapeditor {
if((isWorm(c) || isIvy(c) || isMutantIvy(c)) && c->mov[cdir] &&
!isWorm(c->mov[cdir]) && !isIvy(c->mov[cdir]))
c->mondir = NODIR;
if(c->monst == moMimic) {
c->monst = moNone;
mirror::createMirror(cellwalker(c, cdir, true), 0);
c->monst = moMimic;
}
break;
case 1:
c->item = eItem(paintwhat);
@ -1054,6 +1060,8 @@ namespace mapeditor {
displaymm('d', 8, 8+fs*7, 2, vid.fsize, XLAT("d = draw"), 0);
displaymm('l', 8, 8+fs*8, 2, vid.fsize, XLAT("l = line"), 0);
displaymm('c', 8, 8+fs*9, 2, vid.fsize, XLAT("c = circle"), 0);
int s = size(texture::config.data.pixels_to_draw);
if(s) displaymm(0, 8, 8+fs*11, 2, vid.fsize, its(s), 0);
}
#endif
else {

View File

@ -673,8 +673,9 @@ void wandering() {
}
}
void generateSnake(cell *c, int i) {
void generateSnake(cell *c, int i, int color) {
c->monst = moHexSnake;
c->hitpoints = color;
int cpair = (1<<pattern_threecolor(c)) | (1<<pattern_threecolor(c->mov[i]));
preventbarriers(c);
int len = nonbitrunc ? 2 : ROCKSNAKELENGTH;
@ -689,7 +690,7 @@ void generateSnake(cell *c, int i) {
cell *c3 = c2->mov[i];
if(c3->monst || c3->bardir != NODIR || c3->wall) break;
c2 = c3;
c2->monst = moHexSnakeTail;
c2->monst = moHexSnakeTail; c2->hitpoints = color;
i = (j + (c2->type%4 == 0 ? c2->type/2 : (len%2 ? 2 : c2->type - 2))) % c2->type;
createMov(c2, i);
if(!inpair(c2->mov[i], cpair)) {

View File

@ -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(; 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++) {
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;
}
}

View File

@ -767,7 +767,7 @@ namespace patterns {
if((gp::on? (S3==3) : !weirdhyperbolic) && isWarped(c))
val_warped(c, si);
else {
si.id = ishept(c) ? 1 : 0;
si.id = pseudohept(c) ? 1 : 0;
if(euclid) {
si.dir = ishex1(c) ? 0 : 3;
if(ctof(c)) si.symmetries = 3;
@ -956,6 +956,12 @@ namespace patterns {
else if(a457 && pat == PAT_ZEBRA) {
val_all(c, si, sub, pat);
}
else if(gp::on) {
bool football = (pat == PAT_COLORING && (sub & SPF_FOOTBALL)) || pat == 0;
if(football) val_nopattern(c, si, sub);
else val_threecolors(c, si, sub);
}
else if(pat == PAT_COLORING && (S7 == 4 || euclid || (a38 && gp_threecolor() == 1))) {
val_threecolors(c, si, sub);
@ -1626,6 +1632,7 @@ namespace patterns {
dialog::addBoolItem(s, geometry == g.geo && nonbitrunc == g.nonbitru && whichPattern == g.whichPattern && subpattern_flags == g.subpattern_flags, 'a'+j);
}
bool have_goldberg = S3 == 3 && among(cgroup, cpFootball, cpThree) && !euclid;
if(!(S7&1) && !nonbitrunc) have_goldberg = false; // always start from non-bitruncated
if(have_goldberg) {
dialog::addBoolItem(XLAT("Goldberg"), gp::on, 'G');
dialog::lastItem().value = gp::operation_name();

View File

@ -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)

View File

@ -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; d<S7; d++) if(c->master->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; d<S7; d++) if(h2->move[d] == h1) confusion++;
if(confusion > 1) {
transmatrix T;
confusion = 0;
for(int d=0; d<S7; d++) if(h2->move[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; d<S7; d++) if(h2->move[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; 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) {
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;
}

View File

@ -1269,6 +1269,7 @@ void fillpixel(int x, int y, unsigned col) {
}
void texture_data::undo() {
texture::config.data.pixels_to_draw.clear();
while(!undos.empty()) {
auto p = undos.back();
undos.pop_back();