diff --git a/cell.cpp b/cell.cpp index 94bf0868..2e952bc7 100644 --- a/cell.cpp +++ b/cell.cpp @@ -524,6 +524,9 @@ void cwrevstep(cellwalker& cw) { // very similar to createMove in heptagon.cpp cell *createMov(cell *c, int d) { + if(d<0 || d>= c->type) { + printf("ERROR createmov\n"); + } if(euclid && !c->mov[d]) { eucoord x, y; @@ -641,6 +644,7 @@ void clearcell(cell *c) { DEBMEM ( printf("mov %p [%p] S%d\n", c->mov[t], c->mov[t]->mov[c->spn(t)], c->spn(t)); ) if(c->mov[t]->mov[c->spn(t)] != NULL && c->mov[t]->mov[c->spn(t)] != c) { + printf("type = %d %d -> %d\n", c->type, t, c->spn(t)); printf("cell error\n"); exit(1); } diff --git a/commandline.cpp b/commandline.cpp index ec0cfac9..8e2d5e7d 100644 --- a/commandline.cpp +++ b/commandline.cpp @@ -82,12 +82,9 @@ int arg::readCommon() { shift(); char *c = args(); using namespace patterns; - sym01 = sym02 = sym03 = symRotation = false; + subpattern_flags = 0; while(*c) { - if(*c == '1') sym01 = true; - else if(*c == '2') sym02 = true; - else if(*c == '3') sym03 = true; - else if(*c == '0') symRotation = true; + if(*c >= '0' && *c <= '9') subpattern_flags ^= (*c - '0'); else whichPattern = *c; c++; } diff --git a/graph.cpp b/graph.cpp index f2721632..c5c8f685 100644 --- a/graph.cpp +++ b/graph.cpp @@ -2187,12 +2187,9 @@ int countMinesAround(cell *c) { return mines; } -transmatrix applyPatterndir(cell *c, char patt = patterns::whichPattern) { - transmatrix V = ddspin(c, patterns::patterndir(c, patt), S42); - - if(patterns::reflectPatternAt(c, patt)) - return V * Mirror; - +transmatrix applyPatterndir(cell *c, const patterns::patterninfo& si) { + transmatrix V = ddspin(c, si.dir, S42); + if(si.reflect) return V * Mirror; return V; } @@ -2238,42 +2235,40 @@ void drawZebraFloor(const transmatrix& V, cell *c, int col) { qfloor(c, V, PLAINFLOOR, col); return; } - int i = zebra40(c); - i &= ~3; + auto si = patterns::getpatterninfo(c, 'z', patterns::SPF_SYM0123); int j; - if(nontruncated) j = 4; - else if(i >=4 && i < 16) j = 2; - else if(i >= 16 && i < 28) j = 1; - else if(i >= 28 && i < 40) j = 3; + else if(si.id >=4 && si.id < 16) j = 2; + else if(si.id >= 16 && si.id < 28) j = 1; + else if(si.id >= 28 && si.id < 40) j = 3; else j = 0; - qfloor(c, V, applyPatterndir(c, 'z'), shZebra[j], col); + qfloor(c, V, applyPatterndir(c, si), shZebra[j], col); } void qplainfloor(cell *c, bool warp, const transmatrix &V, int col); void drawReptileFloor(const transmatrix& V, cell *c, int col, bool usefloor) { - int i = zebra40(c); - i &= ~3; + auto si = patterns::getpatterninfo(c, 'z', patterns::SPF_SYM0123); int j; if(!wmescher) j = 4; else if(nontruncated) j = 0; - else if(i < 4) j = 0; - else if(i >=4 && i < 16) j = 1; - else if(i >= 16 && i < 28) j = 2; - else if(i >= 28 && i < 40) j = 3; + else if(si.id < 4) j = 0; + else if(si.id >=4 && si.id < 16) j = 1; + else if(si.id >= 16 && si.id < 28) j = 2; + else if(si.id >= 28 && si.id < 40) j = 3; else j = 4; - - transmatrix V2 = V * applyPatterndir(c, 'z'); + + transmatrix D = applyPatterndir(c, si); + transmatrix V2 = V * D; if(wmescher) { if(usefloor) - qfloor(c, V, applyPatterndir(c, 'z'), shReptile[j][0], darkena(col, 0, 0xFF)); + qfloor(c, V, D, shReptile[j][0], darkena(col, 0, 0xFF)); else queuepoly(V2, shReptile[j][0], darkena(col, 0, 0xFF)); } @@ -2317,24 +2312,26 @@ void drawReptileFloor(const transmatrix& V, cell *c, int col, bool usefloor) { } void drawEmeraldFloor(const transmatrix& V, cell *c, int col) { - int j = -1; - if(!euclid && !nontruncated) { - int i = emeraldval(c) & ~3; - if(i == 8) j = 0; - else if(i == 12) j = 1; - else if(i == 16) j = 2; - else if(i == 20) j = 3; - else if(i == 28) j = 4; - else if(i == 36) j = 5; - } - - int ct6 = ctof(c); + auto si = patterns::getpatterninfo(c, 'f', patterns::SPF_SYM0123); + + int j = -1; - if(j >= 0) - qfloor(c, V, applyPatterndir(c, 'f'), shEmeraldFloor[j], col); - else - qfloor(c, V, CAVEFLOOR, col); + if(si.id == 8) j = 0; + else if(si.id == 12) j = 1; + else if(si.id == 16) j = 2; + else if(si.id == 20) j = 3; + else if(si.id == 28) j = 4; + else if(si.id == 36) j = 5; + + if(j >= 0) { + qfloor(c, V, applyPatterndir(c, si), shEmeraldFloor[j], col); + return; + } + } + + int ct6 = ctof(c); + qfloor(c, V, CAVEFLOOR, col); } double fanframe; @@ -2856,8 +2853,10 @@ void floorShadow(cell *c, const transmatrix& V, int col, bool warp) { else queuepolyat(V, shTriheptaFloorShadow[ctof(c)], col, PPR_WALLSHADOW); } - else - queuepolyat(V * applyPatterndir(c), shTriheptaFloorShadow[ctof(c)], col, PPR_WALLSHADOW); + else { + auto si = patterns::getpatterninfo(c, 0, 0); + queuepolyat(V * applyPatterndir(c, si), shTriheptaFloorShadow[ctof(c)], col, PPR_WALLSHADOW); + } } else if(c->land == laDual && !nontruncated) { if(euclid && ishex1(c)) @@ -2873,17 +2872,15 @@ void floorShadow(cell *c, const transmatrix& V, int col, bool warp) { void plainfloor(cell *c, bool warp, const transmatrix &V, int col, int prio) { if(warp) { if(euclid) { - /* if(ishex1(c)) - queuepolyat(V * pispin * applyPatterndir(c), shTriheptaFloor[0], col, prio); - else - queuepolyat(V * applyPatterndir(c), shTriheptaFloor[ctof(c)], col, prio); */ if(ishex1(c)) queuepolyat(V * pispin, shTriheptaFloor[ctof(c)], col, prio); else queuepolyat(V, shTriheptaFloor[ctof(c)], col, prio); } - else - queuepolyat(V * applyPatterndir(c), shTriheptaFloor[sphere ? ctof(c) : patterns::nopattern(c)], col, prio); + else { + auto si = patterns::getpatterninfo(c, 0, 0); + queuepolyat(V * applyPatterndir(c, si), shTriheptaFloor[sphere ? ctof(c) : si.id], col, prio); + } } else if(c->land == laDual && !nontruncated) { if(euclid && ishex1(c)) @@ -2900,14 +2897,8 @@ void qfloor_eswap(cell *c, const transmatrix& V, const hpcshape& sh, int col); void qplainfloor(cell *c, bool warp, const transmatrix &V, int col) { if(warp) { - if(euclid) { - if(ishex1(c)) - qfloor(c, V, applyPatterndir(c) * pispin, shTriheptaFloor[0], col); - else - qfloor(c, V, applyPatterndir(c), shTriheptaFloor[ctof(c)], col); - } - else - qfloor(c, V, applyPatterndir(c), shTriheptaFloor[sphere ? ctof(c) : patterns::nopattern(c)], col); + auto si = patterns::getpatterninfo(c, 0, 0); + qfloor(c, V, applyPatterndir(c, si), shTriheptaFloor[si.id], col); } else if(c->land == laDual && !nontruncated) qfloor_eswap(c, V, shBigTriangle, col); @@ -3503,7 +3494,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { // floor #if CAP_EDIT - transmatrix Vpdir = V * applyPatterndir(c); + auto si = patterns::getpatterninfo0(c); #endif bool eoh = euclid || nontruncated; @@ -3518,7 +3509,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { } #if CAP_EDIT - if(mapeditor::drawUserShape(Vpdir, mapeditor::cellShapeGroup(), patterns::realpattern(c), + if(mapeditor::drawUserShape(V * applyPatterndir(c, si), mapeditor::cellShapeGroup(), si.id, darkena(fcol, fd, (cmode & sm::DRAW) ? 0xC0 : 0xFF), c)); else if(patterns::whichShape == '7') { @@ -3675,10 +3666,9 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { } else if(isWarped(c) && !nontruncated && !shmup::on) { - int np = patterns::nopattern(c); - if(c->landparam == 1337) np = 0; // for the achievement screenshot - if(np < 13) - qfloor(c, Vf, applyPatterndir(c), shTriheptaFloor[np], darkena(fcol, fd, 0xFF)); + auto si = patterns::getpatterninfo(c, 0, 0); + if(si.id < 13) + qfloor(c, Vf, applyPatterndir(c, si), shTriheptaFloor[si.id], darkena(fcol, fd, 0xFF)); else qfloor(c, Vf, shFloor[ctof(c)], darkena(fcol, fd, 0xFF)); } @@ -3904,15 +3894,15 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { #if CAP_EDIT if(patterns::displaycodes) { - - int labeli = patterns::displaycodes == 1 ? patterns::realpattern(c) : patterns::subpattern(c); + + int pf = patterns::displaycodes == 2 ? patterns::subpattern_flags : 0; + + auto si = patterns::getpatterninfo(c, patterns::whichPattern, pf); - string label = its(labeli); + queuepoly(V * applyPatterndir(c,si), shAsymmetric, darkena(0x000000, 0, 0xC0)); + + string label = its(si.id); queuestr(V, .5, label, 0xFF000000 + forecolor); - - /* transmatrix V2 = V * applyPatterndir(c); - qfloor(c, V2, shNecro, 0x80808080); - qfloor(c, V2, shStatue, 0x80808080); */ } #endif @@ -4582,7 +4572,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { #if CAP_EDIT if((cmode & sm::MAP) && lmouseover && darken == 0 && !mouseout() && - (patterns::whichPattern ? patterns::subpattern(c) == patterns::subpattern(lmouseover) : c == lmouseover)) { + (patterns::whichPattern ? patterns::getpatterninfo0(c).id == patterns::getpatterninfo0(lmouseover).id : c == lmouseover)) { queuecircle(V, .78, 0x00FFFFFF); } diff --git a/hyper.h b/hyper.h index 4398ee56..91f89819 100644 --- a/hyper.h +++ b/hyper.h @@ -654,17 +654,46 @@ extern struct SDL_Surface *s; namespace patterns { extern char whichShape; + extern char whichPattern; - extern bool symRotation, sym01, sym02, sym03; + + static const char PAT_WARP = 0; + static const char PAT_ZEBRA = 'z'; + static const char PAT_EMERALD = 'f'; + static const char PAT_PALACE = 'p'; + static const char PAT_FIELD = 'F'; + static const char PAT_DOWN = 'H'; + static const char PAT_COLORING = 'C'; + static const char PAT_SIBLING = 'S'; + + extern int subpattern_flags; + + static const int SPF_ROT = 1; + static const int SPF_SYM01 = 2; + static const int SPF_SYM02 = 4; + static const int SPF_SYM03 = 8; + static const int SPF_CHANGEROT = 16; + static const int SPF_TWOCOL = 32; + + static const int SPF_SYM0123 = 14; + extern char whichCanvas; extern int displaycodes; int generateCanvas(cell *c); - int realpattern(cell *c, char w = whichPattern); - int patterndir(cell *c, char w = whichPattern); - bool reflectPatternAt(cell *c, char p = whichPattern); - int subpattern(cell *c, char w = whichPattern); + + struct patterninfo { + int id; + int dir; + bool reflect; + }; + + patterninfo getpatterninfo(cell *c, char pat, int sub); + + patterninfo getpatterninfo0(cell *c) { + return getpatterninfo(c, whichPattern, subpattern_flags); + } } namespace mapeditor { @@ -1598,8 +1627,8 @@ void pushThumper(cell *th, cell *cto); template T pick(T x, T y) { return hrand(2) ? x : y; } template T pick(T x, T y, T z) { switch(hrand(3)) { case 0: return x; case 1: return y; case 2: return z; } return x; } template T pick(T x, T y, T z, T v) { switch(hrand(4)) { case 0: return x; case 1: return y; case 2: return z; case 3: return v; } return x; } -template bool among(T x, T y) { return x == y; } -template bool among(T x, T y, U... u) { return x==y || among(x,u...); } +template bool among(T x, V y) { return x == y; } +template bool among(T x, V y, U... u) { return x==y || among(x,u...); } eLand getNewSealand(eLand old); bool createOnSea(eLand old); @@ -2335,3 +2364,5 @@ void queueline(const hyperpoint& H1, const hyperpoint& H2, int col, int prf = 0, hyperpoint ddi0(ld dir, ld dist); extern ld tessf, crossf, hexf, hcrossf, hexhexdist, hexvdist, hepvdist, rhexf; unsigned char& part(int& col, int i); + +transmatrix applyPatterndir(cell *c, const patterns::patterninfo& si); diff --git a/init.cpp b/init.cpp index e6839b3d..6436af17 100644 --- a/init.cpp +++ b/init.cpp @@ -356,6 +356,7 @@ void addMessage(string s, char spamtype = 0); #define a45 (S3 == 4 && S7 == 5) #define a46 (S3 == 4 && S7 == 6) #define a47 (S3 == 4 && S7 == 7) +#define a457 (S3 == 4 && S7 != 6) #define a467 (S3 == 4 && S7 >= 6) #define a38 (S7 == 8) #define sphere4 (sphere && S7 == 4) diff --git a/mapeditor.cpp b/mapeditor.cpp index 381bc277..21ecd436 100644 --- a/mapeditor.cpp +++ b/mapeditor.cpp @@ -28,8 +28,8 @@ namespace mapeditor { void applyModelcell(cell *c) { if(patterns::whichPattern == 'H') return; - int i = patterns::realpattern(c); - cell *c2 = modelcell[i]; + auto si = patterns::getpatterninfo0(c); + cell *c2 = modelcell[si.id]; if(c2) { c->wall = c2->wall; c->land = c2->land; @@ -40,8 +40,11 @@ namespace mapeditor { c->mondir = c2->mondir; c->stuntime = c2->stuntime; c->hitpoints = c2->hitpoints; - if(c2->mondir != NODIR) - c->mondir = (c2->mondir - patterns::patterndir(c2) + patterns::patterndir(c) + MODFIXER) % c->type; + if(c2->mondir != NODIR) { + auto si2 = patterns::getpatterninfo0(c2); + c->mondir = (c2->mondir - si2.dir + si.dir + MODFIXER) % c->type; + // todo reflect + } } } #endif @@ -238,7 +241,7 @@ namespace mapstream { c->hitpoints = loadChar(); if(patterns::whichPattern) - mapeditor::modelcell[patterns::realpattern(c)] = c; + mapeditor::modelcell[patterns::getpatterninfo0(c).id] = c; } int32_t whereami = loadInt(); @@ -498,13 +501,15 @@ namespace mapeditor { if(drawcell == cwt.c) return vid.cs.charid; if(drawcell->monst) return drawcell->monst; if(drawcell->item) return drawcell->item; - return patterns::subpattern(drawcell); + return patterns::getpatterninfo0(drawcell).id; } bool editingShape(int group, int id) { if(group != mapeditor::drawcellShapeGroup()) return false; if(group < 3) return id == drawcellShapeID(); - return patterns::subpattern(id, patterns::whichPattern) == patterns::subpattern(drawcell); + // todo fix this + return id == drawcellShapeID(); + // return patterns::getpatterninfo0(id).id == patterns::getpatterninfo0(drawcell).id; } void editCell(const pair& where) { @@ -649,16 +654,17 @@ namespace mapeditor { c3->aitmp = sval, v.push_back(c3); } + auto si = patterns::getpatterninfo0(where.c); int cdir = where.spin; - if(cdir >= 0) - cdir = cdir - patterns::patterndir(where.c); - int sp = patterns::subpattern(where.c); + if(cdir >= 0) cdir = cdir - si.dir; - for(cell* c2: v) - if(patterns::subpattern(c2) == sp) { - editAt(cellwalker(c2, cdir>=0 ? fixdir(cdir + patterns::patterndir(c2), c2) : -1)); - modelcell[patterns::realpattern(c2)] = c2; + for(cell* c2: v) { + auto si2 = patterns::getpatterninfo0(c2); + if(si2.id == si.id) { + editAt(cellwalker(c2, cdir>=0 ? fixdir(cdir + si2.dir, c2) : -1)); + modelcell[si2.id] = c2; } + } } cellwalker mouseover_cw(bool fix) { @@ -903,7 +909,7 @@ namespace mapeditor { default: line1 = XLAT("floor/pattern"); - line2 = "#" + its(patterns::subpattern(drawcell)); + line2 = "#" + its(patterns::getpatterninfo0(drawcell).id); break; } diff --git a/pattern2.cpp b/pattern2.cpp index f982990c..91cd3e50 100644 --- a/pattern2.cpp +++ b/pattern2.cpp @@ -24,14 +24,8 @@ bool ishex1(cell *c) { else return c->type != S6; } -int val46(cell *c) { - return ctof(c) ? c->master->emeraldval : - ((c->master->emeraldval & 1) ^ ((c->master->emeraldval & 2)>>1) ^ (c->spin(0)&1)) ? 8 : 4; - } - int emeraldval(cell *c) { if(euclid) return eupattern(c); - if(a46) return val46(c); if(sphere) return 0; if(ctof(c)) return c->master->emeraldval >> 3; @@ -68,13 +62,7 @@ int eufifty(cell *c) { } } -int val38(cell *c) { - if(ctof(c)) return (c->master->fiftyval >> 1) & 3; - else return 4 ^ (c->master->fiftyval & 1) ^ (c->spin(0) & 1); - } - int fiftyval(cell *c) { - if(a38) return val38(c); if(euclid) return eufifty(c) * 32; if(sphere || S7>7 || S6>6) return 0; if(ctof(c)) @@ -180,10 +168,14 @@ int fiftyval049(cell *c) { int dir_truncated457(cell *c) { int wset = 0; - for(int i=0; i<4; i++) - if(zebra40(createMov(c, i*2))&2) wset |= (1<master->zebraval/10); else if(a4) { int ws = dir_truncated457(c); if(ws < 0) return -ws; - return 16 + (ws/2); + int tot = 0; + array zebras; + for(int i=0; i<4; i++) { + zebras[i] = zebra40(createMov(c, i*2)); + tot += zebras[i]; + } + + // break cycles + int cod = 0; + int mo = 0; for(int i=0; i<4; i++) if(zebras[i] < zebras[mo]) mo = i; + for(int i=0; i<4; i++) for(int j=1; jmaster->fieldval; - si.id = (d < siblings[d]) ? 0 : 1; - for(int i=0; imaster->move[i]->fieldval; - if(di == siblings[d]) si.dir = i; - } - si.reflect = false; - } - else { - int ids = 0, tids = 0, td = 0; - for(int i=0; imov[i*2]->master->fieldval; - ids |= (1<mov[i*2]->master->fieldval; - if(ids & (1<mov[i*2]->master->fieldval; - if(!(ids & (1<master->fieldval; + si.id = (d < siblings[d]) ? 0 : 1; + if(sub & SPF_ROT) si.id = 0; + for(int i=0; imaster->move[i]->fieldval; + if(di == siblings[d]) si.dir = i; } si.reflect = false; } else { - si.id = 8; - si.dir = 0; // whatever - sphereinfo si2 = valsphere(c->mov[0]); - int di = si2.dir - c->spin(0); - di %= S7; - if(di<0) di += S7; - si.reflect = di > S7/2; - } - } - return si; - } - -namespace patterns { - - int nopattern(cell *c) { - if(isWarped(c) && !euclid) { - int u = ishept(c)?1:0; - int qhex = 0; - for(int v=0; vtype; v++) if(c->mov[v] && !isWarped(c->mov[v])) { - u += 2; - if(!ishept(c->mov[v])) qhex++; + int ids = 0, tids = 0, td = 0; + for(int i=0; imov[i*2]->master->fieldval; + ids |= (1<mov[i*2]->master->fieldval; + if(ids & (1<mov[i*2]->master->fieldval; + if(!(ids & (1<mov[0], si2, sub); + int di = si2.dir - c->spin(0); + di %= S7; + if(di<0) di += S7; + si.reflect = di > S7/2; } - if(u == 8 && qhex == 2) return 12; - if(u == 2 && qhex == 1) return 8; - if(u == 6 && qhex == 2) return 10; - return u; } - return ishept(c) ? 1 : ishex1(c) ? 2 : 0; // 0 to 1 } int downdir(cell *c, cellfunction *cf = coastvalEdge) { @@ -421,252 +414,280 @@ namespace patterns { return neighborId(c, c2); } - int realpattern(cell *c, char code) { - switch(code) { - case 'z': - return zebra40(c); // 4 to 43 - case 'f': - return emeraldval(c); // 44 to 99 - case 'p': { - if(a46) return val46(c); - if(a38) return val38(c); - if(sphere) return valsphere(c).id; - int i = fiftyval049(c); - i *= 4; - if(polara50(c)) i|=1; - if(polarb50(c)) i|=2; - return i; - } - case 'H': - return towerval(c); - case 'F': { - if(euclid) - // use the torus ID - return fieldpattern::fieldval_uniq(c); - else if(nontruncated) - // use the actual field codes - return fieldpattern::fieldval(c).first; - else - // use the small numbers from windmap - return windmap::getId(c); - } - } - return nopattern(c); + void applySym0123(int& i, int sub) { + bool sym01 = sub & SPF_SYM01; + bool sym02 = sub & SPF_SYM02; + bool sym03 = sub & SPF_SYM03; + if((sym01?1:0)+(sym02?1:0)+(sym03?1:0) >= 2) i &= ~3; + if(sym01 && (i&1)) i ^= 1; + if(sym02 && (i&2)) i ^= 2; + if(sym03 && (i&2)) i ^= 3; } - int patterndir46(cell *c, int bits) { - if(ctof(c)) { - int b = c->master->emeraldval & bits; - return (b&1) ^ (b & 2 ? 1 : 0); - } + void val46(cell *c, patterninfo &si, int sub) { + int bits = (sub & SPF_CHANGEROT) ? 1 : 2; + if(ctof(c)) { + si.id = c->master->emeraldval >> 1; + applySym0123(si.id, sub); + int b = c->master->emeraldval & bits; + si.dir = (b&1) ^ (b & 2 ? 1 : 0); + } + else { + if(sub & SPF_TWOCOL) si.id = 4; else - return ((c->mov[0]->master->emeraldval + c->spin(0)) & 1) ? 2 : 0; + si.id = ((c->master->emeraldval & 1) ^ ((c->master->emeraldval & 2)>>1) ^ (c->spin(0)&1)) ? 8 : 4; + si.dir = ((c->mov[0]->master->emeraldval + c->spin(0)) & 1) ? 2 : 0; + if(createMov(c, si.dir)->master->emeraldval & 4) + si.dir += 4; } - - int patterndir38(cell *c) { - if(ctof(c)) return c->master->fiftyval | (c->master->fiftyval & 8 ? 0 : 2); - return 0; + } + + // if(a46) return patterndir46(c, w == PAT_ZEBRA ? 3 : w == PAT_PALACE ? 2 : 1); + + void val457(cell *c, patterninfo &si, int sub) { + si.id = zebra40(c); + applySym0123(si.id, sub); + if(sub & SPF_ROT) { + if(si.id >= 4 && si.id < 7) si.id -= 4; + if(si.id >= 20 && si.id < 23) si.id -= 4; } - - int patterndir457(cell *c) { - if(!ctof(c)) { - int d = dir_truncated457(c); - if(d >= 0) return d; - return 0; - } + if(ctof(c)) { for(int i=0; itype; i++) if((zebra40(createStep(c->master, i + S7/2)->c7)&2) == (zebra40(createStep(c->master, i + 1 + S7/2)->c7)&2)) - return i; - return 0; + si.dir = i; } - - bool reflectPatternAt(cell *c, char p) { - if(p == 'p' && sphere) return valsphere(c).reflect; - if(p == 'p' && polarb50(c)) return true; - if(p == 0) { - int np = nopattern(c); - if(np == 4) { - int d = patterndir(c); - return !isWarped(createMov(c, (d+1)%6)); - } - if(np == 12) { - int d = patterndir(c); - return !isWarped(createMov(c, (d+1)%6)); - } - } - return false; + else { + int d = dir_truncated457(c); + if(d >= 0) si.dir = d; + else si.dir = (zebra40(createMov(c, 0)) & 4) ? 2 : 0; } - - int patterndir(cell *c, char w) { - if(w != 'H') { - if(a46) return patterndir46(c, w == 'z' ? 3 : w == 'p' ? 2 : 1); - if(a4) return patterndir457(c); - if(a38) return patterndir38(c); - if(sphere) return valsphere(c).dir; - } - switch(w) { - case 'z': { - int t = zebra40(c); - - if(euclid) return (t*4) % 6; - - int t4 = t>>2, tcdir = 0; - - if(nontruncated) tcdir = t^1; - - else if(t4 == 10) tcdir = t-20; - else if(t4 >= 4 && t4 < 7) tcdir = 40 + (t&3); - else if(t4 >= 1 && t4 < 4) tcdir = t+12; - else if(t4 >= 7 && t4 < 10) tcdir = t-24; - - for(int i=0; itype; i++) if(c->mov[i] && zebra40(c->mov[i]) == tcdir) - return i; - - // printf("fail to fintd %d -> %d\n", t, tcdir); - - return 0; - } - - case 'f': { - int t = emeraldval(c); - if(euclid) return 0; - int tcdir = 0, tbest = (t&3); - for(int i=0; itype; i++) { - cell *c2 = c->mov[i]; - if(c2) { - int t2 = emeraldval(c2); - if((t&3) == (t2&3) && t2 > tbest) - tbest = t2, tcdir = i; - } - } - return tcdir; - } - - case 'p': { - int tcdir = -1, tbest = -1; - int pa = polara50(c); - int pb = polarb50(c); - for(int i=0; itype; i++) { - cell *c2 = c->mov[i]; - if(c2 && polara50(c2) == pa && polarb50(c2) == pb) { - int t2 = fiftyval049(c2); - if(t2 > tbest) tbest = t2, tcdir = i; - } - } - return tcdir; - } - - case 'H': - return downdir(c); - - case 0: { - if(euclid) return 0; - int u = nopattern(c); - - if(u == 6) { - for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) - return i; - } - - else if(u == 2 || u == 3 || u == 8) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,i))) - return i; - } - - else if(u == 4 || u == 10) { - for(int i=0; itype; i+=2) if(!isWarped(createMov(c,i))) - return i; - } - - else if(u == 6) { - for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) - return i; - } - - else if(u == 5) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+3)%7)) && !isWarped(createMov(c,(i+4)%7))) - return i; - } - - else if(u == 9) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+2)%7)) && !isWarped(createMov(c,(i+5)%7))) - return i; - } - - else if(u == 11) { - for(int i=0; itype; i++) if(isWarped(createMov(c,(i)%7)) && isWarped(createMov(c,(i+1)%7))) - return i; - } - - else if(u == 12) { - for(int i=0; itype; i+=2) if(isWarped(createMov(c,i))) - return i; - } - - else if(u == 7) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+1)%7)) && !isWarped(createMov(c,(i+6)%7))) - return i; - } - - else if(u < 2) return 0; - -#if LOCAL - printf("unhandled: u=%d\n", u); -#endif - } - } - return 0; } + + void val38(cell *c, patterninfo &si, int sub) { + bool symRotation = sub & SPF_ROT; + bool sym01 = sub & SPF_TWOCOL; + + if(ctof(c)) { + if(!symRotation) + si.id = (c->master->fiftyval >> 1) & 3; + si.dir = c->master->fiftyval | (c->master->fiftyval & 8 ? 0 : 2); + } + else { + if(sym01) + si.id = 4; + else + si.id = 4 ^ (c->master->fiftyval & 1) ^ (c->spin(0) & 1); + } + } + + void valEuclid(cell *c, patterninfo &si, int sub) { + bool symRotation = sub & SPF_ROT; + si.id = ishept(c) ? 1 : ishex1(c) ? 2 : 0; + if(sub & SPF_CHANGEROT) + si.dir = (zebra40(c)*4) % 6; + if(symRotation) si.id = 0; + } + + void val_all(cell *c, patterninfo &si, int sub) { + if(a46) val46(c, si, sub); + else if(a38) val38(c, si, sub); + else if(sphere) valSibling(c, si, sub); + else if(euclid) valEuclid(c, si, sub); + else if(a4) val457(c, si, sub); + } + + void val_warped(cell *c, patterninfo& si) { + // use val_all for nicer rotation + val_all(c, si, 0); + // get id: + if(stdhyperbolic && isWarped(c)) { + int u = ishept(c)?1:0; + int qhex = 0; + for(int v=0; vtype; v++) if(c->mov[v] && !isWarped(c->mov[v])) { + u += 2; + if(!ishept(c->mov[v])) qhex++; + } + if(u == 8 && qhex == 2) si.id = 12; + else if(u == 2 && qhex == 1) si.id = 8; + else if(u == 6 && qhex == 2) si.id = 10; + si.id = u; + + if(u == 6) { + for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) + si.dir = i; + } + + else if(u == 2 || u == 3 || u == 8) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,i))) + si.dir = i; + } + + else if(u == 4 || u == 10) { + for(int i=0; itype; i+=2) if(!isWarped(createMov(c,i))) + si.dir = i; + if(u == 4) + si.reflect = !isWarped(createMov(c, (si.dir+1)%6)); + } + + else if(u == 6) { + for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) + si.dir = i; + } + + else if(u == 5) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+3)%7)) && !isWarped(createMov(c,(i+4)%7))) + si.dir = i; + } + + else if(u == 9) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+2)%7)) && !isWarped(createMov(c,(i+5)%7))) + si.dir = i; + } + + else if(u == 11) { + for(int i=0; itype; i++) if(isWarped(createMov(c,(i)%7)) && isWarped(createMov(c,(i+1)%7))) + si.dir = i; + } + + else if(u == 12) { + for(int i=0; itype; i+=2) if(isWarped(createMov(c,i))) { + si.dir = i; + si.reflect = !isWarped(createMov(c, (i+1)%6)); + } + } + + else if(u == 7) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+1)%7)) && !isWarped(createMov(c,(i+6)%7))) + si.dir = i; + } + + } + else { + si.id = ishept(c) ? 1 : 0; + if(euclid) si.dir = ishex1(c) ? 3 : 0; + } + } + char whichPattern = 0; - bool symRotation, sym01, sym02, sym03; + int subpattern_flags; - int subpattern(int i, char w) { - if(euclid) { - if(w == 'p') - return i; - if(w == 'z' || w == 'f') - return (symRotation && (i<3)) ? 0 : i; - } + patterninfo getpatterninfo(cell *c, char pat, int sub) { + bool symRotation = sub & SPF_ROT; + + patterninfo si; + si.dir = 0; si.reflect = false; si.id = ctof(c); - if(a38 && w == 'p') { - if(sym01 && i == 5) i = 4; - if(symRotation && i < 4) i = 0; - return i; - } - - if(w == 'z' || w == 'f' || w == 'p') { - if((sym01?1:0)+(sym02?1:0)+(sym03?1:0) >= 2) i &= ~3; - if(sym01 && (i&1)) i ^= 1; - if(sym02 && (i&2)) i ^= 2; - if(sym03 && (i&2)) i ^= 3; - } - - if(w == 'z' && symRotation) { - if(a4 && !a46) { - if(i >= 4 && i < 7) i -= 4; - } - else { - if(i >= 8 && i < 12) i -= 4; - if(i >= 12 && i < 16) i -= 8; - if(i >= 20 && i < 24) i -= 4; - if(i >= 24 && i < 28) i -= 8; - if(i >= 32 && i < 36) i -= 4; - if(i >= 36 && i < 40) i -= 8; + if(pat == PAT_ZEBRA && stdhyperbolic) { + + si.id = zebra40(c); // 4 to 43 + int t4 = si.id>>2, tcdir = 0; + + if(nontruncated) tcdir = si.id^1; + + else if(t4 == 10) tcdir = si.id-20; + else if(t4 >= 4 && t4 < 7) tcdir = 40 + (si.id&3); + else if(t4 >= 1 && t4 < 4) tcdir = si.id+12; + else if(t4 >= 7 && t4 < 10) tcdir = si.id-24; + + for(int i=0; itype; i++) if(c->mov[i] && zebra40(c->mov[i]) == tcdir) + si.dir = i; + + applySym0123(si.id, sub); + + if(symRotation) { + if(si.id >= 8 && si.id < 12) si.id -= 4; + if(si.id >= 12 && si.id < 16) si.id -= 8; + if(si.id >= 20 && si.id < 24) si.id -= 4; + if(si.id >= 24 && si.id < 28) si.id -= 8; + if(si.id >= 32 && si.id < 36) si.id -= 4; + if(si.id >= 36 && si.id < 40) si.id -= 8; } } - if(w == 'p' && stdhyperbolic && symRotation && i >= 3) - i -= ((i/4-1) % 7) * 4; - - return i; + else if(pat == PAT_EMERALD && (stdhyperbolic || a38)) { + si.id = emeraldval(c); // 44 to 99 + if(!euclid) { + int tcdir = 0, tbest = (si.id&3); + for(int i=0; itype; i++) { + cell *c2 = c->mov[i]; + if(c2) { + int t2 = emeraldval(c2); + if((si.id&3) == (t2&3) && t2 > tbest) + tbest = t2, tcdir = i; + } + } + si.dir = tcdir; + } + applySym0123(si.id, sub); + } + + else if(pat == PAT_PALACE && stdhyperbolic) { + int i = fiftyval049(c); + i *= 4; + if(polara50(c)) i|=1; + if(polarb50(c)) i|=2; + si.id = i; + + int tcdir = -1, tbest = -1; + int pa = polara50(c); + int pb = polarb50(c); + si.reflect = pb; + for(int i=0; itype; i++) { + cell *c2 = c->mov[i]; + if(c2 && polara50(c2) == pa && polarb50(c2) == pb) { + int t2 = fiftyval049(c2); + if(t2 > tbest) tbest = t2, tcdir = i; + } + } + si.dir = tcdir; + applySym0123(si.id, sub); + + if(symRotation && si.id >= 3) + si.id -= ((si.id/4-1) % 7) * 4; + } + + else if(pat == PAT_PALACE && euclid) { + si.id = fiftyval049(c); + } + + else if(pat == PAT_DOWN) { + si.id = towerval(c); + si.dir = downdir(c); + } + + else if(pat == PAT_FIELD) { + if(euclid) + // use the torus ID + si.id = fieldpattern::fieldval_uniq(c); + else if(nontruncated) + // use the actual field codes + si.id = fieldpattern::fieldval(c).first; + else + // use the small numbers from windmap + si.id = windmap::getId(c); + // todo dir + } + + else if(sphere && pat == PAT_SIBLING) { + val_all(c, si, sub); + } + + else if(a457 && pat == PAT_ZEBRA) { + val_all(c, si, sub); + } + + else if(pat == PAT_COLORING && (a46 || euclid)) { + val_all(c, si, sub); + } + + else + val_warped(c, si); + + return si; } - int subpattern(cell *c, char w) { - return subpattern(realpattern(c, w), w); - } - } int geosupport_threecolor() { @@ -689,12 +710,16 @@ int geosupport_graveyard() { int pattern_threecolor(cell *c) { if(a38) { - int i = val38(c); + patterns::patterninfo si; + patterns::val38(c, si, 0); + int i = si.id; if(nontruncated) return i; else return i < 4 ? 0 : (1+(i&1)); } if(a46 && !nontruncated) { - int i = val46(c); + patterns::patterninfo si; + patterns::val46(c, si, 0); + int i = si.id; return i >> 2; } if(S7 == 4) { @@ -861,7 +886,7 @@ namespace patterns { col[2] /= 4; return (0x202020 + col[0] + (col[1] << 8) + (col[2] << 16)) >> (err?2:0); } - if(whichCanvas == 'F') { + if(whichCanvas == PAT_FIELD) { return pseudohept(c) ? 0x202020 : 0xC0C0C0; } if(whichCanvas == 'T') { @@ -919,53 +944,64 @@ namespace patterns { gamescreen(0); } dialog::init(); + + if(stdhyperbolic || a4) + dialog::addBoolItem(XLAT("Zebra Pattern"), (whichPattern == PAT_ZEBRA), PAT_ZEBRA); + + if(stdhyperbolic) + dialog::addBoolItem(XLAT("Emerald Pattern"), (whichPattern == PAT_EMERALD), PAT_EMERALD); + else if(a38) + dialog::addBoolItem(XLAT("broken Emerald Pattern"), (whichPattern == PAT_EMERALD), PAT_EMERALD); + + if(stdhyperbolic || euclid) + dialog::addBoolItem(XLAT("Palace Pattern"), (whichPattern == PAT_PALACE), PAT_PALACE); - if(a46) { - dialog::addBoolItem(XLAT("two colors"), (whichPattern == 'f'), 'f'); - dialog::addBoolItem(XLAT("two colors rotated"), (whichPattern == 'z'), 'z'); - } - else if(a4) { - dialog::addBoolItem(XLAT("Zebra Pattern"), (whichPattern == 'z'), 'z'); - } - else if(a38) { - dialog::addBoolItem(XLAT("Zebra Pattern"), (whichPattern == 'z'), 'z'); - dialog::addBoolItem(XLAT("broken Emerald Pattern"), (whichPattern == 'f'), 'f'); - dialog::addBoolItem(XLAT("rotated pattern"), (whichPattern == 'p'), 'p'); - } - else if(euclid) { - dialog::addBoolItem(XLAT("three colors"), (whichPattern == 'f'), 'f'); - dialog::addBoolItem(XLAT("Palace Pattern"), (whichPattern == 'p'), 'p'); - dialog::addBoolItem(XLAT("three colors rotated"), (whichPattern == 'z'), 'z'); - } - else if(sphere) { - dialog::addBoolItem(XLAT("siblings"), (whichPattern == 'p'), 'p'); - } - else { - if(!stdhyperbolic) - dialog::addInfo("patterns do not work correctly in this geometry!"); + if(a38 || a46 || euclid) + dialog::addBoolItem(XLAT("coloring"), (whichPattern == PAT_COLORING), PAT_COLORING); + + if(sphere) + dialog::addBoolItem(XLAT("siblings"), (whichPattern == PAT_SIBLING), PAT_SIBLING); - dialog::addBoolItem(XLAT("Emerald Pattern"), (whichPattern == 'f'), 'f'); - dialog::addBoolItem(XLAT("Palace Pattern"), (whichPattern == 'p'), 'p'); - dialog::addBoolItem(XLAT("Zebra Pattern"), (whichPattern == 'z'), 'z'); - } if(euclid) - dialog::addBoolItem(XLAT("torus pattern"), (whichPattern == 'F'), 'F'); + dialog::addBoolItem(XLAT("torus pattern"), (whichPattern == PAT_FIELD), PAT_FIELD); else if(sphere) - dialog::addBoolItem(XLAT("single cells"), (whichPattern == 'F'), 'F'); + dialog::addBoolItem(XLAT("single cells"), (whichPattern == PAT_FIELD), PAT_FIELD); else - dialog::addBoolItem(XLAT("field pattern"), (whichPattern == 'F'), 'F'); + dialog::addBoolItem(XLAT("field pattern"), (whichPattern == PAT_FIELD), PAT_FIELD); - if(whichPattern == 'f' && stdhyperbolic) symRotation = true; - if(whichPattern == 'F') ; - else if(!euclid) { - dialog::addBoolItem(XLAT("rotational symmetry"), (symRotation), '0'); - dialog::addBoolItem(XLAT("symmetry 0-1"), (sym01), '1'); - dialog::addBoolItem(XLAT("symmetry 0-2"), (sym02), '2'); - dialog::addBoolItem(XLAT("symmetry 0-3"), (sym03), '3'); + if( + (whichPattern == PAT_EMERALD && (stdhyperbolic || a38)) || + (whichPattern == PAT_PALACE && stdhyperbolic) || + (whichPattern == PAT_ZEBRA && stdhyperbolic) || + (whichPattern == PAT_SIBLING && sphere) || + (whichPattern == PAT_ZEBRA && a457)) { + dialog::addBoolItem(XLAT("rotational symmetry"), subpattern_flags & SPF_ROT, '0'); } - else - dialog::addBoolItem(XLAT("edit all three colors"), (symRotation), '0'); + + if((euclid && whichPattern == PAT_COLORING) || + (a38 && whichPattern == PAT_COLORING)) + dialog::addBoolItem(XLAT("edit all three colors"), subpattern_flags & SPF_ROT, '0'); + if(euclid && whichPattern == PAT_COLORING) + dialog::addBoolItem(XLAT("rotate the color groups"), subpattern_flags & SPF_CHANGEROT, '4'); + + if((a38 && whichPattern == PAT_COLORING && !nontruncated) || + (a46 && whichPattern == PAT_COLORING && !nontruncated) + ) + dialog::addBoolItem(XLAT("edit both truncated colors"), subpattern_flags & SPF_TWOCOL, '5'); + + if( + (whichPattern == PAT_EMERALD && (stdhyperbolic || a38)) || + (whichPattern == PAT_PALACE && stdhyperbolic) || + (whichPattern == PAT_ZEBRA && stdhyperbolic) || + (whichPattern == PAT_COLORING && a46) || + (whichPattern == PAT_ZEBRA && a457) + ) { + dialog::addBoolItem(XLAT("symmetry 0-1"), subpattern_flags & SPF_SYM01, '1'); + dialog::addBoolItem(XLAT("symmetry 0-2"), subpattern_flags & SPF_SYM02, '2'); + dialog::addBoolItem(XLAT("symmetry 0-3"), subpattern_flags & SPF_SYM03, '3'); + } + dialog::addBoolItem(XLAT("display pattern codes (full)"), (displaycodes == 1), 'd'); dialog::addBoolItem(XLAT("display pattern codes (simplified)"), (displaycodes == 2), 's'); @@ -982,21 +1018,19 @@ namespace patterns { keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); - if(uni == 'f' || uni == 'p' || uni == 'z' || uni == 'H' || uni == 'F') { + if(among(uni, PAT_EMERALD, PAT_PALACE, PAT_ZEBRA, PAT_DOWN, PAT_FIELD, PAT_COLORING, PAT_SIBLING)) { if(whichPattern == uni) whichPattern = 0; else whichPattern = uni; mapeditor::modelcell.clear(); } - else if(uni == '0') symRotation = !symRotation; - else if(uni == '1') sym01 = !sym01; - else if(uni == '2') sym02 = !sym02; - else if(uni == '3') sym03 = !sym03; + else if(uni >= '0' && uni <= '5') + subpattern_flags ^= (1 << (uni - '0')); + else if(uni == '6' || uni == '7' || uni == '8') { if(whichShape == uni) whichShape = 0; else whichShape = uni; } - else if(uni == '3') sym03 = !sym03; else if(uni == 'd') displaycodes = displaycodes == 1 ? 0 : 1; else if(uni == 's') displaycodes = displaycodes == 2 ? 0 : 2; @@ -1281,3 +1315,10 @@ namespace linepatterns { } }; + +int val46(cell *c) { + patterns::patterninfo si; + patterns::val46(c, si, 0); + return si.id; + } + diff --git a/patterns.cpp b/patterns.cpp index 9ba60e1e..4834d6cd 100644 --- a/patterns.cpp +++ b/patterns.cpp @@ -7,7 +7,7 @@ // rules for the emeraldvalues of heptagons. int emerald_heptagon(int parent, int dir) { - if(a46) return parent ^ (dir & 1) ^ 2; + if(a46) return parent ^ (dir & 1) ^ 2 ^ (((parent^dir) & 1) << 2); if(S7 == 8 && dir > 3) dir--; diff --git a/polygons.cpp b/polygons.cpp index 6ce09275..13eec19e 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -989,6 +989,8 @@ hpcshape shTerraArmor1, shTerraArmor2, shTerraArmor3, shTerraHead, shTerraFace, shJiangShi, shJiangShiDress, shJiangShiCap1, shJiangShiCap2, + + shAsymmetric, shDodeca; @@ -1039,7 +1041,6 @@ hyperpoint turtlevertex(int u, double x, double y, double z) { return hpxd(scale, x, y, z); } - void finishshape() { last->e = qhpc; double area = 0; @@ -1793,6 +1794,8 @@ void buildpolys() { bshape(shLeafFloor[0], PPR_FLOOR_DRAGON, 1*spzoom6, 313); bshape(shLeafFloor[1], PPR_FLOOR_DRAGON, 1*spzoomd7, 314); + bshape(shAsymmetric, PPR_TEXT, scalef, 374); + bshape(shTriheptaFloor[2], PPR_FLOOR, scalef, 32); bshape(shTriheptaFloor[3], PPR_FLOOR, scalef, 33); bshape(shTriheptaFloor[4], PPR_FLOOR, scalef, 34); @@ -3329,6 +3332,8 @@ NEWSHAPE, 371, 1, 1, -0.013726,-0.304365, 0.244972,-0.147728, 0.266167,0.130112, NEWSHAPE, 372, 1, 1, -0.514563,-0.238476, -0.340659,0.172987, -0.100245,0.368967, 0.214334,0.276255, 0.349294,-0.008293, 0.203063,-0.280225, -0.078470,-0.352806, NEWSHAPE, 373, 1, 1, -0.019312,0.304743, -0.289045,0.177117, -0.127176,-0.240665, 0.007400,-0.336712, 0.257684,-0.184398, 0.234654,0.191587, +NEWSHAPE, 374, 1, 1, -0.229502,-0.051000, 0.320183,0.006447, 0.148302,0.144065, 0.173317,0.054954, -0.253447,0.021298, + NEWSHAPE }; diff --git a/textures.cpp b/textures.cpp index a63f70fd..ae06a02e 100644 --- a/textures.cpp +++ b/textures.cpp @@ -119,16 +119,11 @@ map texture_map; bool applyTextureMap(cell *c, const transmatrix &V, int col) { using namespace patterns; - int t = subpattern(c, whichPattern); + auto si = getpatterninfo0(c); try { - auto& mi = texture_map.at(t); - qfi.spin = Id; + auto& mi = texture_map.at(si.id); + qfi.spin = applyPatterndir(c, si); - int d = patterndir(c, whichPattern); - qfi.spin = qfi.spin * spin(-M_PI * 2 * d / c->type); - if(reflectPatternAt(c)) - qfi.spin = qfi.spin * Mirror; - int n = mi.vertices.size() / 3; qfi.special = false; @@ -160,25 +155,21 @@ void perform_mapping() { glfont_t& f(textures); int tabid = 1; for(auto p: gmatrix) { cell *c = p.first; - int t = subpattern(c, whichPattern); + auto si = getpatterninfo0(c); bool replace = false; - if(!texture_map.count(t)) + if(!texture_map.count(si.id)) replace = true; - else if(p.second[2][2] < texture_map[t].M[2][2]) + else if(p.second[2][2] < texture_map[si.id].M[2][2]) replace = true; if(replace) { - auto& mi = texture_map[t]; + auto& mi = texture_map[si.id]; mi.M = p.second; mi.vertices.clear(); mi.tvertices.clear(); - int d = patterndir(c, whichPattern); - if(d) - mi.M = mi.M * spin(-M_PI * 2 * d / c->type); - if(reflectPatternAt(c, whichPattern)) - mi.M = mi.M * Mirror; + mi.M = mi.M * applyPatterndir(c, si); ld z = ctof(c) ? rhexf : hexvdist; ld base = ctof(c) ? 0 : 0; // -hexshift;